add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
#
# (C) COPYRIGHT 2010 STMicroelectronics R&D Ltd
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file COPYING in the main directory of this archive for
# more details.
#
MALI_DIR := $(srctree)/drivers/stm/mali
# Get ARM release version string
SVN_REV := $(shell [ -e $(MALI_DIR)/version ] && cat $(MALI_DIR)/version)
# Get API version of user-kernel interface by extracting it from the mali_kernel_ioctl.h file
API_VERSION := $(shell grep "\#define _MALI_API_VERSION" $(MALI_DIR)/common/mali_uk_types.h | cut -d' ' -f 3 )
# Driver include paths
ccflags-y := -I$(MALI_DIR) -I$(MALI_DIR)/common -I$(MALI_DIR)/linux -I$(MALI_DIR)/platform
ccflags-y += -I$(MALI_DIR)/linux/license/gpl
# Source files which always are included in a build
OSK_OBJS := $(addprefix ./linux/, \
mali_osk_atomics.o \
mali_osk_irq.o \
mali_osk_locks.o \
mali_osk_low_level_mem.o \
mali_osk_math.o \
mali_osk_memory.o \
mali_osk_misc.o \
mali_osk_mali.o \
mali_osk_notification.o \
mali_osk_time.o \
mali_osk_timers.o)
UKK_OBJS := $(addprefix ./linux/,\
mali_ukk_mem.o \
mali_ukk_gp.o \
mali_ukk_pp.o \
mali_ukk_core.o)
LINUX_OBJS := $(addprefix ./linux/, \
mali_kernel_linux.o \
mali_osk_indir_mmap.o \
mali_ukk_vsync.o \
mali_kernel_sysfs.o)
COMMON_OBJS := $(addprefix ./common/, \
mali_kernel_core.o \
mali_kernel_rendercore.o \
mali_kernel_descriptor_mapping.o \
mali_kernel_vsync.o )
PLATFORM_OBJS := $(addprefix ./platform/stm/, \
mali_platform.o )
ifeq ($(CONFIG_CPU_SUBTYPE_STX7108)$(CONFIG_CPU_SUBTYPE_FLI7510),y)
SOC := stx7108
USING_MMU := 1
USING_UMP := 0
USING_MALI200 := 0
USING_MALI400 := 1
USING_MALI400_L2_CACHE := 1
USING_GP2 := 1
# new for r2p1
ONLY_ZBT := 0
USING_ZBT := 1
USING_OS_MEMORY := 0
USING_PMM := 1
USING_MALI_RUN_TIME_PM := 0
USING_GPU_UTILIZATION := 0
USING_PROFILING := 0
TIMESTAMP := default
USING_MALI_PMM_TESTSUITE := 0
# new for r2p2
OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB := 6
MALI_OBJS := $(OSK_OBJS) $(UKK_OBJS) $(COMMON_OBJS) $(LINUX_OBJS) $(PLATFORM_OBJS)
MALI_OBJS += $(addprefix ./common/, \
mali_kernel_MALI200.o \
mali_kernel_GP2.o \
mali_kernel_mem_mmu.o \
mali_kernel_memory_engine.o \
mali_block_allocator.o \
mali_kernel_mem_os.o \
mali_kernel_l2_cache.o)
endif
ifeq ($(USING_PMM),1)
MALI_OBJS += $(addprefix ./common/pmm/, \
mali_pmm.o \
mali_pmm_policy.o \
mali_pmm_policy_alwayson.o \
mali_pmm_policy_jobcontrol.o \
mali_pmm_state.o )
MALI_OBJS += $(addprefix ./linux/, \
mali_kernel_pm.o \
mali_osk_pm.o \
mali_device_pause_resume.o)
ccflags-y += -I$(MALI_DIR)/common/pmm
endif
ifeq ($(USING_PROFILING),1)
MALI_OBJS += $(addprefix ./common/, \
mali_kernel_profiling.o) \
timestamp-$(TIMESTAMP)/mali_timestamp.o
ccflags-y += -I$(MALI_DIR)/timestamp-$(TIMESTAMP)
endif
ifeq ($(USING_GPU_UTILIZATION),1)
MALI_OBJS += $(addprefix ./common/, \
mali_kernel_utilization.o
endif
MAIL_OBJS += malidrv_build_info.o
# Mali driver defines
ccflags-y += -DUSING_MMU=$(USING_MMU) \
-DMALI_USE_UNIFIED_MEMORY_PROVIDER=0 \
-D_MALI_OSK_SPECIFIC_INDIRECT_MMAP \
-DMALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP \
-DUSING_MALI400=$(USING_MALI400) \
-DUSING_MALI400_L2_CACHE=$(USING_MALI400_L2_CACHE) \
-DSVN_REV=$(SVN_REV) \
-DSVN_REV_STRING=\"$(SVN_REV)\"
# Mali driver defines new for r2p1
ccflags-y += -DUSING_ZBT=$(USING_ZBT) \
-DUSING_OS_MEMORY=$(USING_OS_MEMORY) \
-DONLY_ZBT=$(ONLY_ZBT) \
-DUSING_MALI_PMM=$(USING_PMM) \
-DMALI_PMM_RUNTIME_JOB_CONTROL_ON=$(USING_MALI_RUN_TIME_PM) \
-DMALI_GPU_UTILIZATION=$(USING_GPU_UTILIZATION) \
-DMALI_TIMELINE_PROFILING_ENABLED=$(USING_PROFILING) \
-DMALI_POWER_MGMT_TEST_SUITE=$(USING_MALI_PMM_TESTSUITE)
# Mali driver defines new for r2p2
ccflags-y += -DMALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB)
ifeq ($(shell test $(SUBLEVEL) -gt 32 && echo "OK"),OK)
# MALI_STATE_TRACKING is only supported on Linux kernels from version 2.6.32.
ccflags-y += -DMALI_STATE_TRACKING=1
else
ccflags-y += -DMALI_STATE_TRACKING=0
endif
ifeq ($(CONFIG_STM_MALI_DEBUG),y)
ccflags-y += -DDEBUG
endif
BUILD_DATE := $(shell LANG=C /bin/date "+%a %b %d %Y %H:%m %Z")
CFLAGS_malidrv_build_info.o := -DMALIDRV_SOC="KBUILD_STR($(SOC))" \
-DMALIDRV_KERNELDIR="KBUILD_STR($(KERNELDIR))" \
-DMALIDRV_USING_MMU="KBUILD_STR($(USING_MMU))" \
-DMALIDRV_USING_UMP="KBUILD_STR($(USING_UMP))" \
-DMALIDRV_MMAP_CACHED_PAGES="KBUILD_STR($(MMAP_CACHED_PAGES))" \
-DMALIDRV_USING_MALI200="KBUILD_STR($(USING_MALI200))" \
-DMALIDRV_USING_MALI400="KBUILD_STR($(USING_MALI400))" \
-DMALIDRV_USING_MALI400L2="KBUILD_STR($(USING_MALI400L2))" \
-DMALIDRV_USING_MALIGP2="KBUILD_STR($(USING_MALIGP2))" \
-DMALIDRV_API_VERSION="KBUILD_STR($(API_VERSION))" \
-DMALIDRV_SVN_REV="KBUILD_STR($(SVN_REV))" \
-DMALIDRV_BUILD_DATE="KBUILD_STR($(BUILD_DATE))"
obj-$(CONFIG_STM_MALI) += mali.o
mali-objs := $(MALI_OBJS)
# last line

View File

@@ -0,0 +1,370 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_kernel_core.h"
#include "mali_kernel_memory_engine.h"
#include "mali_block_allocator.h"
#include "mali_osk.h"
#define MALI_BLOCK_SIZE (256UL * 1024UL) /* 256 kB, remember to keep the ()s */
typedef struct block_info
{
struct block_info * next;
} block_info;
/* The structure used as the handle produced by block_allocator_allocate,
* and removed by block_allocator_release */
typedef struct block_allocator_allocation
{
/* The list will be released in reverse order */
block_info *last_allocated;
mali_allocation_engine * engine;
mali_memory_allocation * descriptor;
u32 start_offset;
u32 mapping_length;
} block_allocator_allocation;
typedef struct block_allocator
{
_mali_osk_lock_t *mutex;
block_info * all_blocks;
block_info * first_free;
u32 base;
u32 cpu_usage_adjust;
u32 num_blocks;
} block_allocator;
MALI_STATIC_INLINE u32 get_phys(block_allocator * info, block_info * block);
static mali_physical_memory_allocation_result block_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
static void block_allocator_release(void * ctx, void * handle);
static mali_physical_memory_allocation_result block_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block);
static void block_allocator_release_page_table_block( mali_page_table_block *page_table_block );
static void block_allocator_destroy(mali_physical_memory_allocator * allocator);
mali_physical_memory_allocator * mali_block_allocator_create(u32 base_address, u32 cpu_usage_adjust, u32 size, const char *name)
{
mali_physical_memory_allocator * allocator;
block_allocator * info;
u32 usable_size;
u32 num_blocks;
usable_size = size & ~(MALI_BLOCK_SIZE - 1);
MALI_DEBUG_PRINT(3, ("Mali block allocator create for region starting at 0x%08X length 0x%08X\n", base_address, size));
MALI_DEBUG_PRINT(4, ("%d usable bytes\n", usable_size));
num_blocks = usable_size / MALI_BLOCK_SIZE;
MALI_DEBUG_PRINT(4, ("which becomes %d blocks\n", num_blocks));
if (usable_size == 0)
{
MALI_DEBUG_PRINT(1, ("Memory block of size %d is unusable\n", size));
return NULL;
}
allocator = _mali_osk_malloc(sizeof(mali_physical_memory_allocator));
if (NULL != allocator)
{
info = _mali_osk_malloc(sizeof(block_allocator));
if (NULL != info)
{
info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED, 0, 105);
if (NULL != info->mutex)
{
info->all_blocks = _mali_osk_malloc(sizeof(block_info) * num_blocks);
if (NULL != info->all_blocks)
{
u32 i;
info->first_free = NULL;
info->num_blocks = num_blocks;
info->base = base_address;
info->cpu_usage_adjust = cpu_usage_adjust;
for ( i = 0; i < num_blocks; i++)
{
info->all_blocks[i].next = info->first_free;
info->first_free = &info->all_blocks[i];
}
allocator->allocate = block_allocator_allocate;
allocator->allocate_page_table_block = block_allocator_allocate_page_table_block;
allocator->destroy = block_allocator_destroy;
allocator->ctx = info;
allocator->name = name;
return allocator;
}
_mali_osk_lock_term(info->mutex);
}
_mali_osk_free(info);
}
_mali_osk_free(allocator);
}
return NULL;
}
static void block_allocator_destroy(mali_physical_memory_allocator * allocator)
{
block_allocator * info;
MALI_DEBUG_ASSERT_POINTER(allocator);
MALI_DEBUG_ASSERT_POINTER(allocator->ctx);
info = (block_allocator*)allocator->ctx;
_mali_osk_free(info->all_blocks);
_mali_osk_lock_term(info->mutex);
_mali_osk_free(info);
_mali_osk_free(allocator);
}
MALI_STATIC_INLINE u32 get_phys(block_allocator * info, block_info * block)
{
return info->base + ((block - info->all_blocks) * MALI_BLOCK_SIZE);
}
static mali_physical_memory_allocation_result block_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
{
block_allocator * info;
u32 left;
block_info * last_allocated = NULL;
mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_NONE;
block_allocator_allocation *ret_allocation;
MALI_DEBUG_ASSERT_POINTER(ctx);
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_ASSERT_POINTER(offset);
MALI_DEBUG_ASSERT_POINTER(alloc_info);
info = (block_allocator*)ctx;
left = descriptor->size - *offset;
MALI_DEBUG_ASSERT(0 != left);
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
ret_allocation = _mali_osk_malloc( sizeof(block_allocator_allocation) );
if ( NULL == ret_allocation )
{
/* Failure; try another allocator by returning MALI_MEM_ALLOC_NONE */
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return result;
}
ret_allocation->start_offset = *offset;
ret_allocation->mapping_length = 0;
while ((left > 0) && (info->first_free))
{
block_info * block;
u32 phys_addr;
u32 padding;
u32 current_mapping_size;
block = info->first_free;
info->first_free = info->first_free->next;
block->next = last_allocated;
last_allocated = block;
phys_addr = get_phys(info, block);
padding = *offset & (MALI_BLOCK_SIZE-1);
if (MALI_BLOCK_SIZE - padding < left)
{
current_mapping_size = MALI_BLOCK_SIZE - padding;
}
else
{
current_mapping_size = left;
}
if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, phys_addr + padding, info->cpu_usage_adjust, current_mapping_size))
{
MALI_DEBUG_PRINT(1, ("Mapping of physical memory failed\n"));
result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->start_offset, ret_allocation->mapping_length, (_mali_osk_mem_mapregion_flags_t)0);
/* release all memory back to the pool */
while (last_allocated)
{
/* This relinks every block we've just allocated back into the free-list */
block = last_allocated->next;
last_allocated->next = info->first_free;
info->first_free = last_allocated;
last_allocated = block;
}
break;
}
*offset += current_mapping_size;
left -= current_mapping_size;
ret_allocation->mapping_length += current_mapping_size;
}
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
if (last_allocated)
{
if (left) result = MALI_MEM_ALLOC_PARTIAL;
else result = MALI_MEM_ALLOC_FINISHED;
/* Record all the information about this allocation */
ret_allocation->last_allocated = last_allocated;
ret_allocation->engine = engine;
ret_allocation->descriptor = descriptor;
alloc_info->ctx = info;
alloc_info->handle = ret_allocation;
alloc_info->release = block_allocator_release;
}
else
{
/* Free the allocation information - nothing to be passed back */
_mali_osk_free( ret_allocation );
}
return result;
}
static void block_allocator_release(void * ctx, void * handle)
{
block_allocator * info;
block_info * block, * next;
block_allocator_allocation *allocation;
MALI_DEBUG_ASSERT_POINTER(ctx);
MALI_DEBUG_ASSERT_POINTER(handle);
info = (block_allocator*)ctx;
allocation = (block_allocator_allocation*)handle;
block = allocation->last_allocated;
MALI_DEBUG_ASSERT_POINTER(block);
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
{
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
return;
}
/* unmap */
mali_allocation_engine_unmap_physical(allocation->engine, allocation->descriptor, allocation->start_offset, allocation->mapping_length, (_mali_osk_mem_mapregion_flags_t)0);
while (block)
{
MALI_DEBUG_ASSERT(!((block < info->all_blocks) || (block > (info->all_blocks + info->num_blocks))));
next = block->next;
/* relink into free-list */
block->next = info->first_free;
info->first_free = block;
/* advance the loop */
block = next;
}
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
_mali_osk_free( allocation );}
static mali_physical_memory_allocation_result block_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block)
{
block_allocator * info;
mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
MALI_DEBUG_ASSERT_POINTER(ctx);
MALI_DEBUG_ASSERT_POINTER(block);
info = (block_allocator*)ctx;
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
if (NULL != info->first_free)
{
void * virt;
u32 phys;
u32 size;
block_info * alloc;
alloc = info->first_free;
phys = get_phys(info, alloc); /* Does not modify info or alloc */
size = MALI_BLOCK_SIZE; /* Must be multiple of MALI_MMU_PAGE_SIZE */
virt = _mali_osk_mem_mapioregion( phys, size, "Mali block allocator page tables" );
/* Failure of _mali_osk_mem_mapioregion will result in MALI_MEM_ALLOC_INTERNAL_FAILURE,
* because it's unlikely another allocator will be able to map in. */
if ( NULL != virt )
{
block->ctx = info; /* same as incoming ctx */
block->handle = alloc;
block->phys_base = phys;
block->size = size;
block->release = block_allocator_release_page_table_block;
block->mapping = virt;
info->first_free = alloc->next;
alloc->next = NULL; /* Could potentially link many blocks together instead */
result = MALI_MEM_ALLOC_FINISHED;
}
}
else result = MALI_MEM_ALLOC_NONE;
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return result;
}
static void block_allocator_release_page_table_block( mali_page_table_block *page_table_block )
{
block_allocator * info;
block_info * block, * next;
MALI_DEBUG_ASSERT_POINTER( page_table_block );
info = (block_allocator*)page_table_block->ctx;
block = (block_info*)page_table_block->handle;
MALI_DEBUG_ASSERT_POINTER(info);
MALI_DEBUG_ASSERT_POINTER(block);
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
{
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
return;
}
/* Unmap all the physical memory at once */
_mali_osk_mem_unmapioregion( page_table_block->phys_base, page_table_block->size, page_table_block->mapping );
/** @note This loop handles the case where more than one block_info was linked.
* Probably unnecssary for page table block releasing. */
while (block)
{
next = block->next;
MALI_DEBUG_ASSERT(!((block < info->all_blocks) || (block > (info->all_blocks + info->num_blocks))));
block->next = info->first_free;
info->first_free = block;
block = next;
}
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
}

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_BLOCK_ALLOCATOR_H__
#define __MALI_BLOCK_ALLOCATOR_H__
#include "mali_kernel_memory_engine.h"
mali_physical_memory_allocator * mali_block_allocator_create(u32 base_address, u32 cpu_usage_adjust, u32 size, const char *name);
#endif /* __MALI_BLOCK_ALLOCATOR_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_COMMON_H__
#define __MALI_KERNEL_COMMON_H__
/* Make sure debug is defined when it should be */
#ifndef DEBUG
#if defined(_DEBUG)
#define DEBUG
#endif
#endif
/* The file include several useful macros for error checking, debugging and printing.
* - MALI_PRINTF(...) Do not use this function: Will be included in Release builds.
* - MALI_DEBUG_PRINT(nr, (X) ) Prints the second argument if nr<=MALI_DEBUG_LEVEL.
* - MALI_DEBUG_ERROR( (X) ) Prints an errortext, a source trace, and the given error message.
* - MALI_DEBUG_ASSERT(exp,(X)) If the asserted expr is false, the program will exit.
* - MALI_DEBUG_ASSERT_POINTER(pointer) Triggers if the pointer is a zero pointer.
* - MALI_DEBUG_CODE( X ) The code inside the macro is only compiled in Debug builds.
*
* The (X) means that you must add an extra parenthesis around the argumentlist.
*
* The printf function: MALI_PRINTF(...) is routed to _mali_osk_debugmsg
*
* Suggested range for the DEBUG-LEVEL is [1:6] where
* [1:2] Is messages with highest priority, indicate possible errors.
* [3:4] Is messages with medium priority, output important variables.
* [5:6] Is messages with low priority, used during extensive debugging.
*/
/**
* Fundamental error macro. Reports an error code. This is abstracted to allow us to
* easily switch to a different error reporting method if we want, and also to allow
* us to search for error returns easily.
*
* Note no closing semicolon - this is supplied in typical usage:
*
* MALI_ERROR(MALI_ERROR_OUT_OF_MEMORY);
*/
#define MALI_ERROR(error_code) return (error_code)
/**
* Basic error macro, to indicate success.
* Note no closing semicolon - this is supplied in typical usage:
*
* MALI_SUCCESS;
*/
#define MALI_SUCCESS MALI_ERROR(_MALI_OSK_ERR_OK)
/**
* Basic error macro. This checks whether the given condition is true, and if not returns
* from this function with the supplied error code. This is a macro so that we can override it
* for stress testing.
*
* Note that this uses the do-while-0 wrapping to ensure that we don't get problems with dangling
* else clauses. Note also no closing semicolon - this is supplied in typical usage:
*
* MALI_CHECK((p!=NULL), ERROR_NO_OBJECT);
*/
#define MALI_CHECK(condition, error_code) do { if(!(condition)) MALI_ERROR(error_code); } while(0)
/**
* Error propagation macro. If the expression given is anything other than _MALI_OSK_NO_ERROR,
* then the value is returned from the enclosing function as an error code. This effectively
* acts as a guard clause, and propagates error values up the call stack. This uses a
* temporary value to ensure that the error expression is not evaluated twice.
* If the counter for forcing a failure has been set using _mali_force_error, this error will be
* returned without evaluating the expression in MALI_CHECK_NO_ERROR
*/
#define MALI_CHECK_NO_ERROR(expression) \
do { _mali_osk_errcode_t _check_no_error_result=(expression); \
if(_check_no_error_result != _MALI_OSK_ERR_OK) \
MALI_ERROR(_check_no_error_result); \
} while(0)
/**
* Pointer check macro. Checks non-null pointer.
*/
#define MALI_CHECK_NON_NULL(pointer, error_code) MALI_CHECK( ((pointer)!=NULL), (error_code) )
/**
* Error macro with goto. This checks whether the given condition is true, and if not jumps
* to the specified label using a goto. The label must therefore be local to the function in
* which this macro appears. This is most usually used to execute some clean-up code before
* exiting with a call to ERROR.
*
* Like the other macros, this is a macro to allow us to override the condition if we wish,
* e.g. to force an error during stress testing.
*/
#define MALI_CHECK_GOTO(condition, label) do { if(!(condition)) goto label; } while(0)
/**
* Explicitly ignore a parameter passed into a function, to suppress compiler warnings.
* Should only be used with parameter names.
*/
#define MALI_IGNORE(x) x=x
#define MALI_PRINTF(args) _mali_osk_dbgmsg args;
#define MALI_PRINT_ERROR(args) do{ \
MALI_PRINTF(("Mali: ERR: %s\n" ,__FILE__)); \
MALI_PRINTF((" %s()%4d\n ", __FUNCTION__, __LINE__)) ; \
MALI_PRINTF(args); \
MALI_PRINTF(("\n")); \
} while(0)
#define MALI_PRINT(args) do{ \
MALI_PRINTF(("Mali: ")); \
MALI_PRINTF(args); \
} while (0)
#ifdef DEBUG
extern int mali_debug_level;
#define MALI_DEBUG_CODE(code) code
#define MALI_DEBUG_PRINT(level, args) do { \
if((level) <= mali_debug_level)\
{MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); } \
} while (0)
#define MALI_DEBUG_PRINT_ERROR(args) MALI_PRINT_ERROR(args)
#define MALI_DEBUG_PRINT_IF(level,condition,args) \
if((condition)&&((level) <= mali_debug_level))\
{MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); }
#define MALI_DEBUG_PRINT_ELSE(level, args)\
else if((level) <= mali_debug_level)\
{ MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); }
/**
* @note these variants of DEBUG ASSERTS will cause a debugger breakpoint
* to be entered (see _mali_osk_break() ). An alternative would be to call
* _mali_osk_abort(), on OSs that support it.
*/
#define MALI_DEBUG_PRINT_ASSERT(condition, args) do {if( !(condition)) { MALI_PRINT_ERROR(args); _mali_osk_break(); } } while(0)
#define MALI_DEBUG_ASSERT_POINTER(pointer) do {if( (pointer)== NULL) {MALI_PRINT_ERROR(("NULL pointer " #pointer)); _mali_osk_break();} } while(0)
#define MALI_DEBUG_ASSERT(condition) do {if( !(condition)) {MALI_PRINT_ERROR(("ASSERT failed: " #condition )); _mali_osk_break();} } while(0)
#else /* DEBUG */
#define MALI_DEBUG_CODE(code)
#define MALI_DEBUG_PRINT(string,args) do {} while(0)
#define MALI_DEBUG_PRINT_ERROR(args) do {} while(0)
#define MALI_DEBUG_PRINT_IF(level,condition,args) do {} while(0)
#define MALI_DEBUG_PRINT_ELSE(level,condition,args) do {} while(0)
#define MALI_DEBUG_PRINT_ASSERT(condition,args) do {} while(0)
#define MALI_DEBUG_ASSERT_POINTER(pointer) do {} while(0)
#define MALI_DEBUG_ASSERT(condition) do {} while(0)
#endif /* DEBUG */
/**
* variables from user space cannot be dereferenced from kernel space; tagging them
* with __user allows the GCC compiler to generate a warning. Other compilers may
* not support this so we define it here as an empty macro if the compiler doesn't
* define it.
*/
#ifndef __user
#define __user
#endif
#endif /* __MALI_KERNEL_COMMON_H__ */

View File

@@ -0,0 +1,931 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_subsystem.h"
#include "mali_kernel_mem.h"
#include "mali_kernel_session_manager.h"
#include "mali_kernel_pp.h"
#include "mali_kernel_gp.h"
#include "mali_osk.h"
#include "mali_osk_mali.h"
#include "mali_ukk.h"
#include "mali_kernel_core.h"
#include "mali_kernel_rendercore.h"
#if defined USING_MALI400_L2_CACHE
#include "mali_kernel_l2_cache.h"
#endif
#if USING_MALI_PMM
#include "mali_pmm.h"
#endif /* USING_MALI_PMM */
/* platform specific set up */
#include "mali_platform.h"
/* Initialized when this subsystem is initialized. This is determined by the
* position in subsystems[], and so the value used to initialize this is
* determined at compile time */
static mali_kernel_subsystem_identifier mali_subsystem_core_id = -1;
/** Pointer to table of resource definitions available to the Mali driver.
* _mali_osk_resources_init() sets up the pointer to this table.
*/
static _mali_osk_resource_t *arch_configuration = NULL;
/** Number of resources initialized by _mali_osk_resources_init() */
static u32 num_resources;
static _mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources );
static _mali_osk_errcode_t initialize_subsystems(void);
static void terminate_subsystems(void);
static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id);
static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id);
static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info);
static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue);
static _mali_osk_errcode_t build_system_info(void);
/**
* @brief handler for MEM_VALIDATION resources
*
* This resource handler is common to all memory systems. It provides a default
* means for validating requests to map in external memory via
* _mali_ukk_map_external_mem. In addition, if _mali_ukk_va_to_pa is
* implemented, then _mali_ukk_va_to_pa can make use of this MEM_VALIDATION
* resource.
*
* MEM_VALIDATION also provide a CPU physical to Mali physical address
* translation, for use by _mali_ukk_map_external_mem.
*
* @note MEM_VALIDATION resources are only to handle simple cases where a
* certain physical address range is allowed to be mapped in by any process,
* e.g. a framebuffer at a fixed location. If the implementor has more complex
* mapping requirements, then they must either:
* - implement their own memory validation function
* - or, integrate with UMP.
*
* @param resource The resource to handle (type MEM_VALIDATION)
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource);
/* MEM_VALIDATION handler state */
typedef struct
{
u32 phys_base; /**< Mali physical base of the memory, page aligned */
u32 size; /**< size in bytes of the memory, multiple of page size */
s32 cpu_usage_adjust; /**< Offset to add to Mali Physical address to obtain CPU physical address */
} _mali_mem_validation_range_t;
#define _MALI_MAX_EXT_RANGES 4
typedef struct
{
u32 num_ranges; /**< Number of ranges registered */
_mali_mem_validation_range_t range[_MALI_MAX_EXT_RANGES]; /**< The ranges registered - static allocation for now */
} _mali_mem_validation_t;
static _mali_mem_validation_t mem_validator = {.num_ranges = 0}; /* no ranges registered at the start */
static struct mali_kernel_subsystem mali_subsystem_core =
{
mali_kernel_subsystem_core_setup, /* startup */
mali_kernel_subsystem_core_cleanup, /* shutdown */
NULL, /* load_complete */
mali_kernel_subsystem_core_system_info_fill, /* system_info_fill */
mali_kernel_subsystem_core_session_begin, /* session_begin */
NULL, /* session_end */
NULL, /* broadcast_notification */
#if MALI_STATE_TRACKING
NULL, /* dump_state */
#endif
};
static struct mali_kernel_subsystem * subsystems[] =
{
/* always initialize the hw subsystems first */
/* always included */
&mali_subsystem_memory,
#if USING_MALI_PMM
/* The PMM must be initialized before any cores - including L2 cache */
&mali_subsystem_pmm,
#endif
/* The rendercore subsystem must be initialized before any subsystem based on the
* rendercores is started e.g. mali_subsystem_mali200 and mali_subsystem_gp2 */
&mali_subsystem_rendercore,
/* add reference to the subsystem */
&mali_subsystem_mali200,
/* add reference to the subsystem */
&mali_subsystem_gp2,
#if defined USING_MALI400_L2_CACHE
&mali_subsystem_l2_cache,
#endif
/* always included */
/* NOTE Keep the core entry at the tail of the list */
&mali_subsystem_core
};
#define SUBSYSTEMS_COUNT ( sizeof(subsystems) / sizeof(subsystems[0]) )
/* Pointers to this type available as incomplete struct in mali_kernel_session_manager.h */
struct mali_session_data
{
void * subsystem_data[SUBSYSTEMS_COUNT];
_mali_osk_notification_queue_t * ioctl_queue;
};
static mali_kernel_resource_registrator resource_handler[RESOURCE_TYPE_COUNT] = { NULL, };
/* system info variables */
static _mali_osk_lock_t *system_info_lock = NULL;
static _mali_system_info * system_info = NULL;
static u32 system_info_size = 0;
/* is called from OS specific driver entry point */
_mali_osk_errcode_t mali_kernel_constructor( void )
{
_mali_osk_errcode_t err;
err = mali_platform_init(NULL);
if (_MALI_OSK_ERR_OK != err) goto error1;
err = _mali_osk_init();
if (_MALI_OSK_ERR_OK != err) goto error2;
MALI_DEBUG_PRINT(2, ("\n"));
MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION));
MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__));
MALI_DEBUG_PRINT(2, ("Svn revision: %s\n", SVN_REV_STRING));
err = initialize_subsystems();
if (_MALI_OSK_ERR_OK != err) goto error3;
MALI_PRINT(("Mali device driver %s loaded\n", SVN_REV_STRING));
MALI_SUCCESS;
error3:
MALI_PRINT(("Mali subsystems failed\n"));
_mali_osk_term();
error2:
MALI_PRINT(("Mali device driver init failed\n"));
if (_MALI_OSK_ERR_OK != mali_platform_deinit(NULL))
{
MALI_PRINT(("Failed to deinit platform\n"));
}
error1:
MALI_PRINT(("Failed to init platform\n"));
MALI_ERROR(err);
}
/* is called from OS specific driver exit point */
void mali_kernel_destructor( void )
{
MALI_DEBUG_PRINT(2, ("\n"));
MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION));
terminate_subsystems(); /* subsystems are responsible for their registered resources */
_mali_osk_term();
if (_MALI_OSK_ERR_OK != mali_platform_deinit(NULL))
{
MALI_PRINT(("Failed to deinit platform\n"));
}
MALI_DEBUG_PRINT(2, ("Module unloaded.\n"));
}
_mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources )
{
_mali_osk_resource_t *arch_resource = *arch_configuration;
u32 i;
#if USING_MALI_PMM
u32 is_pmu_first_resource = 1;
#endif /* USING_MALI_PMM */
/* loop over arch configuration */
for (i = 0; i < num_resources; ++i, arch_resource++)
{
if ( (arch_resource->type >= RESOURCE_TYPE_FIRST) &&
(arch_resource->type < RESOURCE_TYPE_COUNT) &&
(NULL != resource_handler[arch_resource->type])
)
{
#if USING_MALI_PMM
if((arch_resource->type != PMU) && (is_pmu_first_resource == 1))
{
_mali_osk_resource_t mali_pmu_virtual_resource;
mali_pmu_virtual_resource.type = PMU;
mali_pmu_virtual_resource.description = "Virtual PMU";
mali_pmu_virtual_resource.base = 0x00000000;
mali_pmu_virtual_resource.cpu_usage_adjust = 0;
mali_pmu_virtual_resource.size = 0;
mali_pmu_virtual_resource.irq = 0;
mali_pmu_virtual_resource.flags = 0;
mali_pmu_virtual_resource.mmu_id = 0;
mali_pmu_virtual_resource.alloc_order = 0;
MALI_CHECK_NO_ERROR(resource_handler[mali_pmu_virtual_resource.type](&mali_pmu_virtual_resource));
}
is_pmu_first_resource = 0;
#endif /* USING_MALI_PMM */
MALI_CHECK_NO_ERROR(resource_handler[arch_resource->type](arch_resource));
/* the subsystem shutdown process will release all the resources already registered */
}
else
{
MALI_DEBUG_PRINT(1, ("No handler installed for resource %s, type %d\n", arch_resource->description, arch_resource->type));
MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
}
}
MALI_SUCCESS;
}
static _mali_osk_errcode_t initialize_subsystems(void)
{
int i, j;
_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; /* default error code */
MALI_CHECK_NON_NULL(system_info_lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0 ), _MALI_OSK_ERR_FAULT);
for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i)
{
if (NULL != subsystems[i]->startup)
{
/* the subsystem has a startup function defined */
err = subsystems[i]->startup(i); /* the subsystem identifier is the offset in our subsystems array */
if (_MALI_OSK_ERR_OK != err) goto cleanup;
}
}
for (j = 0; j < (int)SUBSYSTEMS_COUNT; ++j)
{
if (NULL != subsystems[j]->load_complete)
{
/* the subsystem has a load_complete function defined */
err = subsystems[j]->load_complete(j);
if (_MALI_OSK_ERR_OK != err) goto cleanup;
}
}
/* All systems loaded and resources registered */
/* Build system info */
if (_MALI_OSK_ERR_OK != build_system_info()) goto cleanup;
MALI_SUCCESS; /* all ok */
cleanup:
/* i is index of subsystem which failed to start, all indices before that has to be shut down */
for (i = i - 1; i >= 0; --i)
{
/* the subsystem identifier is the offset in our subsystems array */
/* Call possible shutdown notficiation functions */
if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i);
}
_mali_osk_lock_term( system_info_lock );
MALI_ERROR(err); /* err is what the module which failed its startup returned, or the default */
}
static void terminate_subsystems(void)
{
int i;
/* shut down subsystems in reverse order from startup */
for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i)
{
/* the subsystem identifier is the offset in our subsystems array */
if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i);
}
if (system_info_lock) _mali_osk_lock_term( system_info_lock );
}
void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data)
{
int i;
for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i)
{
if (NULL != subsystems[i]->broadcast_notification)
{
subsystems[i]->broadcast_notification(message, data);
}
}
}
static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id)
{
mali_subsystem_core_id = id;
/* Register our own resources */
MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MEM_VALIDATION, mali_kernel_core_resource_mem_validation));
/* parse the arch resource definition and tell all the subsystems */
/* this is why the core subsystem has to be specified last in the subsystem array */
MALI_CHECK_NO_ERROR(_mali_osk_resources_init(&arch_configuration, &num_resources));
MALI_CHECK_NO_ERROR(register_resources(&arch_configuration, num_resources));
/* resource parsing succeeded and the subsystem have corretly accepted their resources */
MALI_SUCCESS;
}
static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id)
{
_mali_osk_resources_term(&arch_configuration, num_resources);
}
static _mali_osk_errcode_t build_system_info(void)
{
unsigned int i;
int err = _MALI_OSK_ERR_FAULT;
_mali_system_info * new_info, * cleanup;
_mali_core_info * current_core;
_mali_mem_info * current_mem;
u32 new_size = 0;
/* create a new system info struct */
MALI_CHECK_NON_NULL(new_info = (_mali_system_info *)_mali_osk_malloc(sizeof(_mali_system_info)), _MALI_OSK_ERR_NOMEM);
_mali_osk_memset(new_info, 0, sizeof(_mali_system_info));
/* if an error happens during any of the system_info_fill calls cleanup the new info structs */
cleanup = new_info;
/* ask each subsystems to fill in their info */
for (i = 0; i < SUBSYSTEMS_COUNT; ++i)
{
if (NULL != subsystems[i]->system_info_fill)
{
err = subsystems[i]->system_info_fill(new_info);
if (_MALI_OSK_ERR_OK != err) goto error_exit;
}
}
/* building succeeded, calculate the size */
/* size needed of the system info struct itself */
new_size = sizeof(_mali_system_info);
/* size needed for the cores */
for (current_core = new_info->core_info; NULL != current_core; current_core = current_core->next)
{
new_size += sizeof(_mali_core_info);
}
/* size needed for the memory banks */
for (current_mem = new_info->mem_info; NULL != current_mem; current_mem = current_mem->next)
{
new_size += sizeof(_mali_mem_info);
}
/* lock system info access so a user wont't get a corrupted version */
_mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW );
/* cleanup the old one */
cleanup = system_info;
/* set new info */
system_info = new_info;
system_info_size = new_size;
/* we're safe */
_mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW );
/* ok result */
err = _MALI_OSK_ERR_OK;
/* we share the cleanup routine with the error case */
error_exit:
if (NULL == cleanup) MALI_ERROR((_mali_osk_errcode_t)err); /* no cleanup needed, return what err contains */
/* cleanup */
/* delete all the core info structs */
while (NULL != cleanup->core_info)
{
current_core = cleanup->core_info;
cleanup->core_info = cleanup->core_info->next;
_mali_osk_free(current_core);
}
/* delete all the mem info struct */
while (NULL != cleanup->mem_info)
{
current_mem = cleanup->mem_info;
cleanup->mem_info = cleanup->mem_info->next;
_mali_osk_free(current_mem);
}
/* delete the system info struct itself */
_mali_osk_free(cleanup);
/* return whatever err is, we could end up here in both the error and success cases */
MALI_ERROR((_mali_osk_errcode_t)err);
}
_mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args )
{
MALI_DEBUG_ASSERT_POINTER(args);
MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
/* check compatability */
if ( args->version == _MALI_UK_API_VERSION )
{
args->compatible = 1;
}
else
{
args->compatible = 0;
}
args->version = _MALI_UK_API_VERSION; /* report our version */
/* success regardless of being compatible or not */
MALI_SUCCESS;
}
_mali_osk_errcode_t _mali_ukk_get_system_info_size(_mali_uk_get_system_info_size_s *args)
{
MALI_DEBUG_ASSERT_POINTER(args);
args->size = system_info_size;
MALI_SUCCESS;
}
_mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args )
{
_mali_core_info * current_core;
_mali_mem_info * current_mem;
_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
void * current_write_pos, ** current_patch_pos;
u32 adjust_ptr_base;
/* check input */
MALI_DEBUG_ASSERT_POINTER(args);
MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS);
/* lock the system info */
_mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW );
/* first check size */
if (args->size < system_info_size) goto exit_when_locked;
/* we build a copy of system_info in the user space buffer specified by the user and
* patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may
* indicate a different base address for patching the pointers (normally the
* address of the provided system_info buffer would be used). This is helpful when
* the system_info buffer needs to get copied to user space and the pointers need
* to be in user space.
*/
if (0 == args->ukk_private)
{
adjust_ptr_base = (u32)args->system_info;
}
else
{
adjust_ptr_base = args->ukk_private;
}
/* copy each struct into the buffer, and update its pointers */
current_write_pos = (void *)args->system_info;
/* first, the master struct */
_mali_osk_memcpy(current_write_pos, system_info, sizeof(_mali_system_info));
/* advance write pointer */
current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_system_info));
/* first we write the core info structs, patch starts at master's core_info pointer */
current_patch_pos = (void **)((u32)args->system_info + offsetof(_mali_system_info, core_info));
for (current_core = system_info->core_info; NULL != current_core; current_core = current_core->next)
{
/* patch the pointer pointing to this core */
*current_patch_pos = (void*)(adjust_ptr_base + ((u32)current_write_pos - (u32)args->system_info));
/* copy the core info */
_mali_osk_memcpy(current_write_pos, current_core, sizeof(_mali_core_info));
/* update patch pos */
current_patch_pos = (void **)((u32)current_write_pos + offsetof(_mali_core_info, next));
/* advance write pos in memory */
current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_core_info));
}
/* patching of last patch pos is not needed, since we wrote NULL there in the first place */
/* then we write the mem info structs, patch starts at master's mem_info pointer */
current_patch_pos = (void **)((u32)args->system_info + offsetof(_mali_system_info, mem_info));
for (current_mem = system_info->mem_info; NULL != current_mem; current_mem = current_mem->next)
{
/* patch the pointer pointing to this core */
*current_patch_pos = (void*)(adjust_ptr_base + ((u32)current_write_pos - (u32)args->system_info));
/* copy the core info */
_mali_osk_memcpy(current_write_pos, current_mem, sizeof(_mali_mem_info));
/* update patch pos */
current_patch_pos = (void **)((u32)current_write_pos + offsetof(_mali_mem_info, next));
/* advance write pos in memory */
current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_mem_info));
}
/* patching of last patch pos is not needed, since we wrote NULL there in the first place */
err = _MALI_OSK_ERR_OK;
exit_when_locked:
_mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW );
MALI_ERROR(err);
}
_mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args )
{
_mali_osk_errcode_t err;
_mali_osk_notification_t * notification;
_mali_osk_notification_queue_t *queue;
/* check input */
MALI_DEBUG_ASSERT_POINTER(args);
MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id);
/* if the queue does not exist we're currently shutting down */
if (NULL == queue)
{
MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n"));
args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS;
MALI_SUCCESS;
}
/* receive a notification, might sleep */
err = _mali_osk_notification_queue_receive(queue, &notification);
if (_MALI_OSK_ERR_OK != err)
{
MALI_ERROR(err); /* errcode returned, pass on to caller */
}
/* copy the buffer to the user */
args->type = (_mali_uk_notification_type)notification->notification_type;
_mali_osk_memcpy(&args->data, notification->result_buffer, notification->result_buffer_size);
/* finished with the notification */
_mali_osk_notification_delete( notification );
MALI_SUCCESS; /* all ok */
}
_mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args )
{
_mali_osk_notification_t * notification;
_mali_osk_notification_queue_t *queue;
/* check input */
MALI_DEBUG_ASSERT_POINTER(args);
MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id);
/* if the queue does not exist we're currently shutting down */
if (NULL == queue)
{
MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n"));
MALI_SUCCESS;
}
notification = _mali_osk_notification_create(args->type, 0);
if ( NULL == notification)
{
MALI_PRINT_ERROR( ("Failed to create notification object\n")) ;
return _MALI_OSK_ERR_NOMEM;
}
_mali_osk_notification_queue_send(queue, notification);
MALI_SUCCESS; /* all ok */
}
static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info)
{
MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS);
info->drivermode = _MALI_DRIVER_MODE_NORMAL;
MALI_SUCCESS;
}
static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue)
{
MALI_CHECK_NON_NULL(slot, _MALI_OSK_ERR_INVALID_ARGS);
*slot = queue;
MALI_SUCCESS;
}
/* MEM_VALIDATION resource handler */
static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource)
{
/* Check restrictions on page alignment */
MALI_CHECK( 0 == (resource->base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT );
MALI_CHECK( 0 == (resource->size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT );
MALI_CHECK( 0 == (resource->cpu_usage_adjust & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT );
/* Add new range to the end of the list */
if( _MALI_MAX_EXT_RANGES == mem_validator.num_ranges )
{
MALI_PRINTF( ("Memory Validator '%s' Unable to register another physical range - increase its size\n",resource->description) );
MALI_ERROR( _MALI_OSK_ERR_FAULT );
}
mem_validator.range[mem_validator.num_ranges].phys_base = resource->base;
mem_validator.range[mem_validator.num_ranges].size = resource->size;
mem_validator.range[mem_validator.num_ranges].cpu_usage_adjust = resource->cpu_usage_adjust;
mem_validator.num_ranges ++;
MALI_DEBUG_PRINT( 2, ("Memory Validator '%s' configured for Mali phys addr base=0x%08X, size=0x%08X, cpu_adjust=0x%08X\n",
resource->description, resource->base, resource->size, resource->cpu_usage_adjust ));
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size )
{
u32 mali_phys_base = 1;
u32 idx;
for( idx=0; idx<mem_validator.num_ranges; ++idx)
{
if ( *phys_base >= mem_validator.range[idx].phys_base
&& (*phys_base + size) >= mem_validator.range[idx].phys_base
&& *phys_base <= (mem_validator.range[idx].phys_base + mem_validator.range[idx].size)
&& (*phys_base + size) <= (mem_validator.range[idx].phys_base + mem_validator.range[idx].size) )
{
mali_phys_base = *phys_base - mem_validator.range[idx].cpu_usage_adjust;
}
}
MALI_CHECK( 1 == ( mali_phys_base ), _MALI_OSK_ERR_FAULT );
MALI_CHECK( 0 == ( mali_phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT );
MALI_CHECK( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT );
MALI_CHECK_NO_ERROR( mali_kernel_core_validate_mali_phys_range( mali_phys_base, size ) );
*phys_base = mali_phys_base;
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size )
{
u32 idx;
MALI_CHECK_GOTO( 0 == ( phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), failure );
MALI_CHECK_GOTO( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), failure );
for( idx=0; idx< mem_validator.num_ranges; ++idx)
{
if ( phys_base >= mem_validator.range[idx].phys_base
&& (phys_base + size) >= mem_validator.range[idx].phys_base
&& phys_base <= (mem_validator.range[idx].phys_base + mem_validator.range[idx].size)
&& (phys_base + size) <= (mem_validator.range[idx].phys_base + mem_validator.range[idx].size) )
{
MALI_SUCCESS;
}
}
failure:
MALI_PRINTF( ("*******************************************************************************\n") );
MALI_PRINTF( ("MALI PHYSICAL RANGE VALIDATION ERROR!\n") );
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("We failed to validate a Mali-Physical range that the user-side wished to map in\n") );
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("It is likely that the user-side wished to do Direct Rendering, but a suitable\n") );
MALI_PRINTF( ("address range validation mechanism has not been correctly setup\n") );
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_base, size) );
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("The following regions are currently configured\n") );
for( idx=0; idx< mem_validator.num_ranges; ++idx)
{
MALI_PRINTF( (" phys_base=0x%08X, size=0x%08X\n", mem_validator.range[idx].phys_base, mem_validator.range[idx].size) );
}
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("Please refer to the ARM Mali Software Integration Guide for more information.\n") );
MALI_PRINTF( ("\n") );
MALI_PRINTF( ("*******************************************************************************\n") );
MALI_ERROR( _MALI_OSK_ERR_FAULT );
}
_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler)
{
MALI_CHECK(type < RESOURCE_TYPE_COUNT, _MALI_OSK_ERR_INVALID_ARGS);
MALI_DEBUG_ASSERT(NULL == resource_handler[type]); /* A handler for resource already exists */
resource_handler[type] = handler;
MALI_SUCCESS;
}
void * mali_kernel_session_manager_slot_get(struct mali_session_data * session_data, int id)
{
MALI_DEBUG_ASSERT_POINTER(session_data);
if(id >= SUBSYSTEMS_COUNT) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: id %d out of range\n", id)); return NULL; }
if (NULL == session_data) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: got NULL session data\n")); return NULL; }
return session_data->subsystem_data[id];
}
_mali_osk_errcode_t _mali_ukk_open(void **context)
{
int i;
_mali_osk_errcode_t err;
struct mali_session_data * session_data;
/* allocated struct to track this session */
session_data = (struct mali_session_data *)_mali_osk_malloc(sizeof(struct mali_session_data));
MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM);
_mali_osk_memset(session_data->subsystem_data, 0, sizeof(session_data->subsystem_data));
/* create a response queue for this session */
session_data->ioctl_queue = _mali_osk_notification_queue_init();
if (NULL == session_data->ioctl_queue)
{
_mali_osk_free(session_data);
MALI_ERROR(_MALI_OSK_ERR_NOMEM);
}
MALI_DEBUG_PRINT(3, ("Session starting\n"));
/* call session_begin on all subsystems */
for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i)
{
if (NULL != subsystems[i]->session_begin)
{
/* subsystem has a session_begin */
err = subsystems[i]->session_begin(session_data, &session_data->subsystem_data[i], session_data->ioctl_queue);
MALI_CHECK_GOTO(err == _MALI_OSK_ERR_OK, cleanup);
}
}
*context = (void*)session_data;
MALI_DEBUG_PRINT(3, ("Session started\n"));
MALI_SUCCESS;
cleanup:
MALI_DEBUG_PRINT(2, ("Session startup failed\n"));
/* i is index of subsystem which failed session begin, all indices before that has to be ended */
/* end subsystem sessions in the reverse order they where started in */
for (i = i - 1; i >= 0; --i)
{
if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]);
}
_mali_osk_notification_queue_term(session_data->ioctl_queue);
_mali_osk_free(session_data);
/* return what the subsystem which failed session start returned */
MALI_ERROR(err);
}
_mali_osk_errcode_t _mali_ukk_close(void **context)
{
int i;
struct mali_session_data * session_data;
MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS);
session_data = (struct mali_session_data *)*context;
MALI_DEBUG_PRINT(2, ("Session ending\n"));
/* end subsystem sessions in the reverse order they where started in */
for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i)
{
if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]);
}
_mali_osk_notification_queue_term(session_data->ioctl_queue);
_mali_osk_free(session_data);
*context = NULL;
MALI_DEBUG_PRINT(2, ("Session has ended\n"));
MALI_SUCCESS;
}
#if USING_MALI_PMM
_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only )
{
switch( core )
{
case MALI_PMM_CORE_GP:
MALI_CHECK_NO_ERROR(maligp_signal_power_up(queue_only));
break;
#if defined USING_MALI400_L2_CACHE
case MALI_PMM_CORE_L2:
if( !queue_only )
{
/* Enable L2 cache due to power up */
mali_kernel_l2_cache_do_enable();
/* Invalidate the cache on power up */
MALI_DEBUG_PRINT(5, ("L2 Cache: Invalidate all\n"));
MALI_CHECK_NO_ERROR(mali_kernel_l2_cache_invalidate_all());
}
break;
#endif
case MALI_PMM_CORE_PP0:
MALI_CHECK_NO_ERROR(malipp_signal_power_up(0, queue_only));
break;
case MALI_PMM_CORE_PP1:
MALI_CHECK_NO_ERROR(malipp_signal_power_up(1, queue_only));
break;
case MALI_PMM_CORE_PP2:
MALI_CHECK_NO_ERROR(malipp_signal_power_up(2, queue_only));
break;
case MALI_PMM_CORE_PP3:
MALI_CHECK_NO_ERROR(malipp_signal_power_up(3, queue_only));
break;
default:
/* Unknown core */
MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power up: %d\n", core) );
MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS );
}
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only )
{
switch( core )
{
case MALI_PMM_CORE_GP:
MALI_CHECK_NO_ERROR(maligp_signal_power_down(immediate_only));
break;
#if defined USING_MALI400_L2_CACHE
case MALI_PMM_CORE_L2:
/* Nothing to do */
break;
#endif
case MALI_PMM_CORE_PP0:
MALI_CHECK_NO_ERROR(malipp_signal_power_down(0, immediate_only));
break;
case MALI_PMM_CORE_PP1:
MALI_CHECK_NO_ERROR(malipp_signal_power_down(1, immediate_only));
break;
case MALI_PMM_CORE_PP2:
MALI_CHECK_NO_ERROR(malipp_signal_power_down(2, immediate_only));
break;
case MALI_PMM_CORE_PP3:
MALI_CHECK_NO_ERROR(malipp_signal_power_down(3, immediate_only));
break;
default:
/* Unknown core */
MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power down: %d\n", core) );
MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS );
}
MALI_SUCCESS;
}
#endif
#if MALI_STATE_TRACKING
u32 _mali_kernel_core_dump_state(char* buf, u32 size)
{
int i, n;
char *original_buf = buf;
for (i = 0; i < SUBSYSTEMS_COUNT; ++i)
{
if (NULL != subsystems[i]->dump_state)
{
n = subsystems[i]->dump_state(buf, size);
size -= n;
buf += n;
}
}
#if USING_MALI_PMM
n = mali_pmm_dump_os_thread_state(buf, size);
size -= n;
buf += n;
#endif
/* Return number of bytes written to buf */
return (u32)(buf - original_buf);
}
#endif

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_CORE_H__
#define __MALI_KERNEL_CORE_H__
#include "mali_osk.h"
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_pmm.h"
#include "mali_pmm_system.h"
#endif
_mali_osk_errcode_t mali_kernel_constructor( void );
void mali_kernel_destructor( void );
/**
* @brief Tranlate CPU physical to Mali physical addresses.
*
* This function is used to convert CPU physical addresses to Mali Physical
* addresses, such that _mali_ukk_map_external_mem may be used to map them
* into Mali. This will be used by _mali_ukk_va_to_mali_pa.
*
* This function only supports physically contiguous regions.
*
* A default implementation is provided, which uses a registered MEM_VALIDATION
* resource to do a static translation. Only an address range which will lie
* in the range specified by MEM_VALIDATION will be successfully translated.
*
* If a more complex, or non-static translation is required, then the
* implementor has the following options:
* - Rewrite this function to provide such a translation
* - Integrate the provider of the memory with UMP.
*
* @param[in,out] phys_base pointer to the page-aligned base address of the
* physical range to be translated
*
* @param[in] size size of the address range to be translated, which must be a
* multiple of the physical page size.
*
* @return on success, _MALI_OSK_ERR_OK and *phys_base is translated. If the
* cpu physical address range is not in the valid range, then a suitable
* _mali_osk_errcode_t error.
*
*/
_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size );
/**
* @brief Validate a Mali physical address range.
*
* This function is used to ensure that an address range passed to
* _mali_ukk_map_external_mem is allowed to be mapped into Mali.
*
* This function only supports physically contiguous regions.
*
* A default implementation is provided, which uses a registered MEM_VALIDATION
* resource to do a static translation. Only an address range which will lie
* in the range specified by MEM_VALIDATION will be successfully validated.
*
* If a more complex, or non-static validation is required, then the
* implementor has the following options:
* - Rewrite this function to provide such a validation
* - Integrate the provider of the memory with UMP.
*
* @param phys_base page-aligned base address of the Mali physical range to be
* validated.
*
* @param size size of the address range to be validated, which must be a
* multiple of the physical page size.
*
* @return _MALI_OSK_ERR_OK if the Mali physical range is valid. Otherwise, a
* suitable _mali_osk_errcode_t error.
*
*/
_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size );
#if USING_MALI_PMM
/**
* @brief Signal a power up on a Mali core.
*
* This function flags a core as powered up.
* For PP and GP cores it calls functions that move the core from a power off
* queue into the idle queue ready to run jobs. It also tries to schedule any
* pending jobs to run on it.
*
* This function will fail if the core is not powered off - either running or
* already idle.
*
* @param core The PMM core id to power up.
* @param queue_only When MALI_TRUE only re-queue the core - do not reset.
*
* @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a
* suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only );
/**
* @brief Signal a power down on a Mali core.
*
* This function flags a core as powered down.
* For PP and GP cores it calls functions that move the core from an idle
* queue into the power off queue.
*
* This function will fail if the core is not idle - either running or
* already powered down.
*
* @param core The PMM core id to power up.
* @param immediate_only Do not set the core to pending power down if it can't
* power down immediately
*
* @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a
* suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only );
#endif
/**
* Flag to indicate whether or not mali_benchmark is turned on.
*/
extern int mali_benchmark;
#endif /* __MALI_KERNEL_CORE_H__ */

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_kernel_descriptor_mapping.h"
#include "mali_osk.h"
#include "mali_osk_bitops.h"
#define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1))
/**
* Allocate a descriptor table capable of holding 'count' mappings
* @param count Number of mappings in the table
* @return Pointer to a new table, NULL on error
*/
static mali_descriptor_table * descriptor_table_alloc(int count);
/**
* Free a descriptor table
* @param table The table to free
*/
static void descriptor_table_free(mali_descriptor_table * table);
mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int max_entries)
{
mali_descriptor_mapping * map = _mali_osk_calloc(1, sizeof(mali_descriptor_mapping));
init_entries = MALI_PAD_INT(init_entries);
max_entries = MALI_PAD_INT(max_entries);
if (NULL != map)
{
map->table = descriptor_table_alloc(init_entries);
if (NULL != map->table)
{
#if !USING_MMU
map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 20);
#else
map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 116);
#endif
if (NULL != map->lock)
{
_mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */
map->max_nr_mappings_allowed = max_entries;
map->current_nr_mappings = init_entries;
return map;
}
descriptor_table_free(map->table);
}
_mali_osk_free(map);
}
return NULL;
}
void mali_descriptor_mapping_destroy(mali_descriptor_mapping * map)
{
descriptor_table_free(map->table);
_mali_osk_lock_term(map->lock);
_mali_osk_free(map);
}
_mali_osk_errcode_t mali_descriptor_mapping_allocate_mapping(mali_descriptor_mapping * map, void * target, int *odescriptor)
{
_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
int new_descriptor;
MALI_DEBUG_ASSERT_POINTER(map);
MALI_DEBUG_ASSERT_POINTER(odescriptor);
_mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
new_descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings);
if (new_descriptor == map->current_nr_mappings)
{
/* no free descriptor, try to expand the table */
mali_descriptor_table * new_table, * old_table;
if (map->current_nr_mappings >= map->max_nr_mappings_allowed) goto unlock_and_exit;
map->current_nr_mappings += BITS_PER_LONG;
new_table = descriptor_table_alloc(map->current_nr_mappings);
if (NULL == new_table) goto unlock_and_exit;
old_table = map->table;
_mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG);
_mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*));
map->table = new_table;
descriptor_table_free(old_table);
}
/* we have found a valid descriptor, set the value and usage bit */
_mali_osk_set_nonatomic_bit(new_descriptor, map->table->usage);
map->table->mappings[new_descriptor] = target;
*odescriptor = new_descriptor;
err = _MALI_OSK_ERR_OK;
unlock_and_exit:
_mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
MALI_ERROR(err);
}
void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void (*callback)(int, void*))
{
int i;
MALI_DEBUG_ASSERT_POINTER(map);
MALI_DEBUG_ASSERT_POINTER(callback);
_mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
/* id 0 is skipped as it's an reserved ID not mapping to anything */
for (i = 1; i < map->current_nr_mappings; ++i)
{
if (_mali_osk_test_bit(i, map->table->usage))
{
callback(i, map->table->mappings[i]);
}
}
_mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
}
_mali_osk_errcode_t mali_descriptor_mapping_get(mali_descriptor_mapping * map, int descriptor, void** target)
{
_mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT;
MALI_DEBUG_ASSERT_POINTER(map);
_mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
{
*target = map->table->mappings[descriptor];
result = _MALI_OSK_ERR_OK;
}
else *target = NULL;
_mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
MALI_ERROR(result);
}
_mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, int descriptor, void * target)
{
_mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT;
_mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
{
map->table->mappings[descriptor] = target;
result = _MALI_OSK_ERR_OK;
}
_mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
MALI_ERROR(result);
}
void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor)
{
_mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
{
map->table->mappings[descriptor] = NULL;
_mali_osk_clear_nonatomic_bit(descriptor, map->table->usage);
}
_mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
}
static mali_descriptor_table * descriptor_table_alloc(int count)
{
mali_descriptor_table * table;
table = _mali_osk_calloc(1, sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count));
if (NULL != table)
{
table->usage = (u32*)((u8*)table + sizeof(mali_descriptor_table));
table->mappings = (void**)((u8*)table + sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG));
}
return table;
}
static void descriptor_table_free(mali_descriptor_table * table)
{
_mali_osk_free(table);
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_kernel_descriptor_mapping.h
*/
#ifndef __MALI_KERNEL_DESCRIPTOR_MAPPING_H__
#define __MALI_KERNEL_DESCRIPTOR_MAPPING_H__
#include "mali_osk.h"
/**
* The actual descriptor mapping table, never directly accessed by clients
*/
typedef struct mali_descriptor_table
{
u32 * usage; /**< Pointer to bitpattern indicating if a descriptor is valid/used or not */
void** mappings; /**< Array of the pointers the descriptors map to */
} mali_descriptor_table;
/**
* The descriptor mapping object
* Provides a separate namespace where we can map an integer to a pointer
*/
typedef struct mali_descriptor_mapping
{
_mali_osk_lock_t *lock; /**< Lock protecting access to the mapping object */
int max_nr_mappings_allowed; /**< Max number of mappings to support in this namespace */
int current_nr_mappings; /**< Current number of possible mappings */
mali_descriptor_table * table; /**< Pointer to the current mapping table */
} mali_descriptor_mapping;
/**
* Create a descriptor mapping object
* Create a descriptor mapping capable of holding init_entries growable to max_entries
* @param init_entries Number of entries to preallocate memory for
* @param max_entries Number of entries to max support
* @return Pointer to a descriptor mapping object, NULL on failure
*/
mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int max_entries);
/**
* Destroy a descriptor mapping object
* @param map The map to free
*/
void mali_descriptor_mapping_destroy(mali_descriptor_mapping * map);
/**
* Allocate a new mapping entry (descriptor ID)
* Allocates a new entry in the map.
* @param map The map to allocate a new entry in
* @param target The value to map to
* @return The descriptor allocated, a negative value on error
*/
_mali_osk_errcode_t mali_descriptor_mapping_allocate_mapping(mali_descriptor_mapping * map, void * target, int *descriptor);
/**
* Get the value mapped to by a descriptor ID
* @param map The map to lookup the descriptor id in
* @param descriptor The descriptor ID to lookup
* @param target Pointer to a pointer which will receive the stored value
* @return 0 on successful lookup, negative on error
*/
_mali_osk_errcode_t mali_descriptor_mapping_get(mali_descriptor_mapping * map, int descriptor, void** target);
/**
* Set the value mapped to by a descriptor ID
* @param map The map to lookup the descriptor id in
* @param descriptor The descriptor ID to lookup
* @param target Pointer to replace the current value with
* @return 0 on successful lookup, negative on error
*/
_mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, int descriptor, void * target);
/**
* Call the specified callback function for each descriptor in map.
* Entire function is mutex protected.
* @param map The map to do callbacks for
* @param callback A callback function which will be calle for each entry in map
*/
void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void (*callback)(int, void*));
/**
* Free the descriptor ID
* For the descriptor to be reused it has to be freed
* @param map The map to free the descriptor from
* @param descriptor The descriptor ID to free
*/
void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor);
#endif /* __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ */

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_GP2_H__
#define __MALI_KERNEL_GP2_H__
extern struct mali_kernel_subsystem mali_subsystem_gp2;
#if USING_MALI_PMM
_mali_osk_errcode_t maligp_signal_power_up( mali_bool queue_only );
_mali_osk_errcode_t maligp_signal_power_down( mali_bool immediate_only );
#endif
#endif /* __MALI_KERNEL_GP2_H__ */

View File

@@ -0,0 +1,515 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_osk_list.h"
#include "mali_kernel_core.h"
#include "mali_kernel_pp.h"
#include "mali_kernel_subsystem.h"
#include "regs/mali_200_regs.h"
#include "mali_kernel_rendercore.h"
#include "mali_kernel_l2_cache.h"
/**
* Size of the Mali L2 cache registers in bytes
*/
#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30
/**
* Mali L2 cache register numbers
* Used in the register read/write routines.
* See the hardware documentation for more information about each register
*/
typedef enum mali_l2_cache_register {
MALI400_L2_CACHE_REGISTER_STATUS = 0x0002,
/*unused = 0x0003 */
MALI400_L2_CACHE_REGISTER_COMMAND = 0x0004, /**< Misc cache commands, e.g. clear */
MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0005,
MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0006, /**< Limit of outstanding read requests */
MALI400_L2_CACHE_REGISTER_ENABLE = 0x0007, /**< Enable misc cache features */
MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0008,
MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0009,
MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x000A,
MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x000B,
} mali_l2_cache_register;
/**
* Mali L2 cache commands
* These are the commands that can be sent to the Mali L2 cache unit
*/
typedef enum mali_l2_cache_command
{
MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */
/* Read HW TRM carefully before adding/using other commands than the clear above */
} mali_l2_cache_command;
/**
* Mali L2 cache commands
* These are the commands that can be sent to the Mali L2 cache unit
*/
typedef enum mali_l2_cache_enable
{
MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */
MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */
MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */
} mali_l2_cache_enable;
/**
* Mali L2 cache status bits
*/
typedef enum mali_l2_cache_status
{
MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */
MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */
} mali_l2_cache_status;
/**
* Definition of the L2 cache core struct
* Used to track a L2 cache unit in the system.
* Contains information about the mapping of the registers
*/
typedef struct mali_kernel_l2_cache_core
{
unsigned long base; /**< Physical address of the registers */
mali_io_address mapped_registers; /**< Virtual mapping of the registers */
u32 mapping_size; /**< Size of registers in bytes */
_mali_osk_list_t list; /**< Used to link multiple cache cores into a list */
_mali_osk_lock_t *lock; /**< Serialize all L2 cache commands */
} mali_kernel_l2_cache_core;
#define MALI400_L2_MAX_READS_DEFAULT 0x1C
int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT;
/**
* Mali L2 cache subsystem startup function
* Called by the driver core when the driver is loaded.
*
* @param id Identifier assigned by the core to the L2 cache subsystem
* @return 0 on success, negative on error
*/
static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id);
/**
* Mali L2 cache subsystem shutdown function
* Called by the driver core when the driver is unloaded.
* Cleans up
* @param id Identifier assigned by the core to the L2 cache subsystem
*/
static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id);
/**
* L2 cache subsystem complete notification function.
* Called by the driver core when all drivers have loaded and all resources has been registered
* @param id Identifier assigned by the core to the L2 cache subsystem
* @return 0 on success, negative on error
*/
static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id);
/**
* Mali L2 cache subsystem's notification handler for a Mali L2 cache resource instances.
* Registered with the core during startup.
* Called by the core for each Mali L2 cache described in the active architecture's config.h file.
* @param resource The resource to handle (type MALI400L2)
* @return 0 if the Mali L2 cache was found and initialized, negative on error
*/
static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource);
/**
* Write to a L2 cache register
* Writes the given value to the specified register
* @param unit The L2 cache to write to
* @param reg The register to write to
* @param val The value to write to the register
*/
static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val);
/**
* Invalidate specified L2 cache
* @param cache The L2 cache to invalidate
* @return 0 if Mali L2 cache was successfully invalidated, otherwise error
*/
static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache);
/*
The fixed Mali L2 cache system's mali subsystem interface implementation.
We currently handle module and session life-time management.
*/
struct mali_kernel_subsystem mali_subsystem_l2_cache =
{
mali_l2_cache_initialize, /**< startup */
mali_l2_cache_terminate, /**< shutdown */
mali_l2_cache_load_complete, /**< load_complete */
NULL, /**< system_info_fill */
NULL, /**< session_begin */
NULL, /**< session_end */
NULL, /**< broadcast_notification */
#if MALI_STATE_TRACKING
NULL, /**< dump_state */
#endif
};
static _MALI_OSK_LIST_HEAD(caches_head);
/* called during module init */
static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id)
{
_mali_osk_errcode_t err;
MALI_IGNORE( id );
MALI_DEBUG_PRINT(2, ( "Mali L2 cache system initializing\n"));
_MALI_OSK_INIT_LIST_HEAD(&caches_head);
/* This will register the function for adding Mali L2 cache cores to the subsystem */
err = _mali_kernel_core_register_resource_handler(MALI400L2, mali_l2_cache_core_create);
MALI_ERROR(err);
}
/* called if/when our module is unloaded */
static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
MALI_DEBUG_PRINT(2, ( "Mali L2 cache system terminating\n"));
/* loop over all L2 cache units and shut them down */
_MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list )
{
/* reset to defaults */
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT);
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT);
/* remove from the list of cacges on the system */
_mali_osk_list_del( &cache->list );
/* release resources */
_mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers );
_mali_osk_mem_unreqregion( cache->base, cache->mapping_size );
_mali_osk_lock_term( cache->lock );
_mali_osk_free( cache );
#if USING_MALI_PMM
/* Unregister the L2 cache with the PMM */
malipmm_core_unregister( MALI_PMM_CORE_L2 );
#endif
}
}
static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource)
{
_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT ;
mali_kernel_l2_cache_core * cache = NULL;
MALI_DEBUG_PRINT(2, ( "Creating Mali L2 cache: %s\n", resource->description));
#if USING_MALI_PMM
/* Register the L2 cache with the PMM */
err = malipmm_core_register( MALI_PMM_CORE_L2 );
if( _MALI_OSK_ERR_OK != err )
{
MALI_DEBUG_PRINT(1, ( "Failed to register L2 cache unit with PMM"));
return err;
}
#endif
err = _mali_osk_mem_reqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE, resource->description);
MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup_requestmem_failed);
/* Reset error that might be passed out */
err = _MALI_OSK_ERR_FAULT;
cache = _mali_osk_malloc(sizeof(mali_kernel_l2_cache_core));
MALI_CHECK_GOTO( NULL != cache, err_cleanup);
cache->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 104 );
MALI_CHECK_GOTO( NULL != cache->lock, err_cleanup);
/* basic setup */
_MALI_OSK_INIT_LIST_HEAD(&cache->list);
cache->base = resource->base;
cache->mapping_size = MALI400_L2_CACHE_REGISTERS_SIZE;
/* map the registers */
cache->mapped_registers = _mali_osk_mem_mapioregion( cache->base, cache->mapping_size, resource->description );
MALI_CHECK_GOTO( NULL != cache->mapped_registers, err_cleanup);
/* Invalidate cache (just to keep it in a known state at startup) */
err = mali_kernel_l2_cache_invalidate_all_cache(cache);
MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup);
/* add to our list of L2 caches */
_mali_osk_list_add( &cache->list, &caches_head );
MALI_SUCCESS;
err_cleanup:
/* This cleanup used when resources have been requested successfully */
if ( NULL != cache )
{
if (NULL != cache->mapped_registers)
{
_mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers);
}
else
{
MALI_DEBUG_PRINT(1, ( "Failed to map Mali L2 cache registers at 0x%08lX\n", cache->base));
}
if( NULL != cache->lock )
{
_mali_osk_lock_term( cache->lock );
}
else
{
MALI_DEBUG_PRINT(1, ( "Failed to allocate a lock for handling a L2 cache unit"));
}
_mali_osk_free( cache );
}
else
{
MALI_DEBUG_PRINT(1, ( "Failed to allocate memory for handling a L2 cache unit"));
}
/* A call is to request region, so this must always be reversed */
_mali_osk_mem_unreqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE);
#if USING_MALI_PMM
malipmm_core_unregister( MALI_PMM_CORE_L2 );
#endif
return err;
err_cleanup_requestmem_failed:
MALI_DEBUG_PRINT(1, ("Failed to request Mali L2 cache '%s' register address space at (0x%08X - 0x%08X)\n",
resource->description, resource->base, resource->base + MALI400_L2_CACHE_REGISTERS_SIZE - 1) );
#if USING_MALI_PMM
malipmm_core_unregister( MALI_PMM_CORE_L2 );
#endif
return err;
}
static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val)
{
_mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val);
}
static u32 mali_l2_cache_register_read(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg)
{
return _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32));
}
void mali_kernel_l2_cache_do_enable(void)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
/* loop over all L2 cache units and enable them*/
_MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
{
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE);
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads);
}
}
static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id)
{
mali_kernel_l2_cache_do_enable();
MALI_DEBUG_PRINT(2, ( "Mali L2 cache system load complete\n"));
MALI_SUCCESS;
}
static _mali_osk_errcode_t mali_kernel_l2_cache_send_command(mali_kernel_l2_cache_core *cache, u32 reg, u32 val)
{
int i = 0;
const int loop_count = 100000;
/*
* Grab lock in order to send commands to the L2 cache in a serialized fashion.
* The L2 cache will ignore commands if it is busy.
*/
_mali_osk_lock_wait(cache->lock, _MALI_OSK_LOCKMODE_RW);
/* First, wait for L2 cache command handler to go idle */
for (i = 0; i < loop_count; i++)
{
if (!(_mali_osk_mem_ioread32(cache->mapped_registers , (u32)MALI400_L2_CACHE_REGISTER_STATUS * sizeof(u32)) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY))
{
break;
}
}
if (i == loop_count)
{
_mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW);
MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n"));
MALI_ERROR( _MALI_OSK_ERR_FAULT );
}
/* then issue the command */
mali_l2_cache_register_write(cache, reg, val);
_mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW);
MALI_SUCCESS;
}
static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache)
{
return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL);
}
_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
/* loop over all L2 cache units and invalidate them */
_MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
{
MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_all_cache(cache) );
}
MALI_SUCCESS;
}
static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page_cache(mali_kernel_l2_cache_core *cache, u32 page)
{
return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, page);
}
_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
/* loop over all L2 cache units and invalidate them */
_MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
{
MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_page_cache(cache, page) );
}
MALI_SUCCESS;
}
void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
int reset0 = force_reset;
int reset1 = force_reset;
MALI_DEBUG_CODE(
int changed0 = 0;
int changed1 = 0;
)
/* loop over all L2 cache units and activate the counters on them */
_MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
{
u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0);
u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1);
if (src0 != cur_src0)
{
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, src0);
MALI_DEBUG_CODE(changed0 = 1;)
reset0 = 1;
}
if (src1 != cur_src1)
{
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, src1);
MALI_DEBUG_CODE(changed1 = 1;)
reset1 = 1;
}
if (reset0)
{
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0, 0);
}
if (reset1)
{
mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1, 0);
}
MALI_DEBUG_PRINT(5, ("L2 cache counters set: SRC0=%u, CHANGED0=%d, RESET0=%d, SRC1=%u, CHANGED1=%d, RESET1=%d\n",
src0, changed0, reset0,
src1, changed1, reset1));
}
}
void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1)
{
mali_kernel_l2_cache_core * cache, *temp_cache;
int first_time = 1;
*src0 = 0;
*src1 = 0;
*val0 = 0;
*val1 = 0;
/* loop over all L2 cache units and read the counters */
_MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
{
u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0);
u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1);
u32 cur_val0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0);
u32 cur_val1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1);
MALI_DEBUG_PRINT(5, ("L2 cache counters get: SRC0=%u, VAL0=%u, SRC1=%u, VAL1=%u\n", cur_src0, cur_val0, cur_src1, cur_val1));
if (first_time)
{
*src0 = cur_src0;
*src1 = cur_src1;
first_time = 0;
}
if (*src0 == cur_src0 && *src1 == cur_src1)
{
*val0 += cur_val0;
*val1 += cur_val1;
}
else
{
MALI_DEBUG_PRINT(1, ("Warning: Mali L2 caches has different performance counters set, not retrieving data\n"));
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_L2_CACHE_H__
#define __MALI_KERNEL_L2_CACHE_H__
#include "mali_osk.h"
#include "mali_kernel_subsystem.h"
extern struct mali_kernel_subsystem mali_subsystem_l2_cache;
_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void);
_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page);
void mali_kernel_l2_cache_do_enable(void);
void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset);
void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1);
#endif /* __MALI_KERNEL_L2_CACHE_H__ */

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_MEM_H__
#define __MALI_KERNEL_MEM_H__
#include "mali_kernel_subsystem.h"
extern struct mali_kernel_subsystem mali_subsystem_memory;
#endif /* __MALI_KERNEL_MEM_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_MEM_MMU_H__
#define __MALI_KERNEL_MEM_MMU_H__
#include "mali_kernel_session_manager.h"
/**
* Lookup a MMU core by ID.
* @param id ID of the MMU to find
* @return NULL if ID not found or valid, non-NULL if a core was found.
*/
void* mali_memory_core_mmu_lookup(u32 id);
/**
* Activate a user session with its address space on the given MMU.
* If the session can't be activated due to that the MMU is busy and
* a callback pointer is given, the callback will be called once the MMU becomes idle.
* If the same callback pointer is registered multiple time it will only be called once.
* Nested activations are supported.
* Each call must be matched by a call to @see mali_memory_core_mmu_release_address_space_reference
*
* @param mmu The MMU to activate the address space on
* @param mali_session_data The user session object which address space to activate
* @param callback Pointer to the function to call when the MMU becomes idle
* @param callback_arg Argument given to the callback
* @return 0 if the address space was activated, -EBUSY if the MMU was busy, -EFAULT in all other cases.
*/
int mali_memory_core_mmu_activate_page_table(void* mmu_ptr, struct mali_session_data * mali_session_data, void(*callback)(void*), void * callback_argument);
/**
* Release a reference to the current active address space.
* Once the last reference is released any callback(s) registered will be called before the function returns
*
* @note Caution must be shown calling this function with locks held due to that callback can be called
* @param mmu The mmu to release a reference to the active address space of
*/
void mali_memory_core_mmu_release_address_space_reference(void* mmu);
/**
* Soft reset of MMU - needed after power up
*
* @param mmu_ptr The MMU pointer registered with the relevant core
*/
void mali_kernel_mmu_reset(void * mmu_ptr);
void mali_kernel_mmu_force_bus_reset(void * mmu_ptr);
/**
* Unregister a previously registered callback.
* @param mmu The MMU to unregister the callback on
* @param callback The function to unregister
*/
void mali_memory_core_mmu_unregister_callback(void* mmu, void(*callback)(void*));
#endif /* __MALI_KERNEL_MEM_MMU_H__ */

View File

@@ -0,0 +1,309 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_kernel_core.h"
#include "mali_kernel_memory_engine.h"
#include "mali_osk.h"
typedef struct os_allocation
{
u32 num_pages;
u32 offset_start;
mali_allocation_engine * engine;
mali_memory_allocation * descriptor;
} os_allocation;
typedef struct os_allocator
{
_mali_osk_lock_t *mutex;
/**
* Maximum number of pages to allocate from the OS
*/
u32 num_pages_max;
/**
* Number of pages allocated from the OS
*/
u32 num_pages_allocated;
/** CPU Usage adjustment (add to mali physical address to get cpu physical address) */
u32 cpu_usage_adjust;
} os_allocator;
static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block);
static void os_allocator_release(void * ctx, void * handle);
static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block );
static void os_allocator_destroy(mali_physical_memory_allocator * allocator);
mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u32 cpu_usage_adjust, const char *name)
{
mali_physical_memory_allocator * allocator;
os_allocator * info;
max_allocation = (max_allocation + _MALI_OSK_CPU_PAGE_SIZE-1) & ~(_MALI_OSK_CPU_PAGE_SIZE-1);
MALI_DEBUG_PRINT(2, ("Mali OS memory allocator created with max allocation size of 0x%X bytes, cpu_usage_adjust 0x%08X\n", max_allocation, cpu_usage_adjust));
allocator = _mali_osk_malloc(sizeof(mali_physical_memory_allocator));
if (NULL != allocator)
{
info = _mali_osk_malloc(sizeof(os_allocator));
if (NULL != info)
{
info->num_pages_max = max_allocation / _MALI_OSK_CPU_PAGE_SIZE;
info->num_pages_allocated = 0;
info->cpu_usage_adjust = cpu_usage_adjust;
info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, 106);
if (NULL != info->mutex)
{
allocator->allocate = os_allocator_allocate;
allocator->allocate_page_table_block = os_allocator_allocate_page_table_block;
allocator->destroy = os_allocator_destroy;
allocator->ctx = info;
allocator->name = name;
return allocator;
}
_mali_osk_free(info);
}
_mali_osk_free(allocator);
}
return NULL;
}
static void os_allocator_destroy(mali_physical_memory_allocator * allocator)
{
os_allocator * info;
MALI_DEBUG_ASSERT_POINTER(allocator);
MALI_DEBUG_ASSERT_POINTER(allocator->ctx);
info = (os_allocator*)allocator->ctx;
_mali_osk_lock_term(info->mutex);
_mali_osk_free(info);
_mali_osk_free(allocator);
}
static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
{
mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_NONE;
u32 left;
os_allocator * info;
os_allocation * allocation;
int pages_allocated = 0;
_mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
MALI_DEBUG_ASSERT_POINTER(ctx);
MALI_DEBUG_ASSERT_POINTER(engine);
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_ASSERT_POINTER(offset);
MALI_DEBUG_ASSERT_POINTER(alloc_info);
info = (os_allocator*)ctx;
left = descriptor->size - *offset;
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
/** @note this code may not work on Linux, or may require a more complex Linux implementation */
allocation = _mali_osk_malloc(sizeof(os_allocation));
if (NULL != allocation)
{
u32 os_mem_max_usage = info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE;
allocation->offset_start = *offset;
allocation->num_pages = ((left + _MALI_OSK_CPU_PAGE_SIZE - 1) & ~(_MALI_OSK_CPU_PAGE_SIZE - 1)) >> _MALI_OSK_CPU_PAGE_ORDER;
MALI_DEBUG_PRINT(6, ("Allocating page array of size %d bytes\n", allocation->num_pages * sizeof(struct page*)));
while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max) && _mali_osk_mem_check_allocated(os_mem_max_usage))
{
err = mali_allocation_engine_map_physical(engine, descriptor, *offset, MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, info->cpu_usage_adjust, _MALI_OSK_CPU_PAGE_SIZE);
if ( _MALI_OSK_ERR_OK != err)
{
if ( _MALI_OSK_ERR_NOMEM == err)
{
/* 'Partial' allocation (or, out-of-memory on first page) */
break;
}
MALI_DEBUG_PRINT(1, ("Mapping of physical memory failed\n"));
/* Fatal error, cleanup any previous pages allocated. */
if ( pages_allocated > 0 )
{
mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*pages_allocated, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
/* (*offset) doesn't need to be restored; it will not be used by the caller on failure */
}
pages_allocated = 0;
result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
break;
}
/* Loop iteration */
if (left < _MALI_OSK_CPU_PAGE_SIZE) left = 0;
else left -= _MALI_OSK_CPU_PAGE_SIZE;
pages_allocated++;
*offset += _MALI_OSK_CPU_PAGE_SIZE;
}
/* Loop termination; decide on result */
if (pages_allocated)
{
MALI_DEBUG_PRINT(6, ("Allocated %d pages\n", pages_allocated));
if (left) result = MALI_MEM_ALLOC_PARTIAL;
else result = MALI_MEM_ALLOC_FINISHED;
/* Some OS do not perform a full cache flush (including all outer caches) for uncached mapped memory.
* They zero the memory through a cached mapping, then flush the inner caches but not the outer caches.
* This is required for MALI to have the correct view of the memory.
*/
_mali_osk_cache_ensure_uncached_range_flushed( (void *)descriptor, allocation->offset_start, pages_allocated *_MALI_OSK_CPU_PAGE_SIZE );
allocation->num_pages = pages_allocated;
allocation->engine = engine; /* Necessary to make the engine's unmap call */
allocation->descriptor = descriptor; /* Necessary to make the engine's unmap call */
info->num_pages_allocated += pages_allocated;
MALI_DEBUG_PRINT(6, ("%d out of %d pages now allocated\n", info->num_pages_allocated, info->num_pages_max));
alloc_info->ctx = info;
alloc_info->handle = allocation;
alloc_info->release = os_allocator_release;
}
else
{
MALI_DEBUG_PRINT(6, ("Releasing pages array due to no pages allocated\n"));
_mali_osk_free( allocation );
}
}
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return result;
}
static void os_allocator_release(void * ctx, void * handle)
{
os_allocator * info;
os_allocation * allocation;
mali_allocation_engine * engine;
mali_memory_allocation * descriptor;
MALI_DEBUG_ASSERT_POINTER(ctx);
MALI_DEBUG_ASSERT_POINTER(handle);
info = (os_allocator*)ctx;
allocation = (os_allocation*)handle;
engine = allocation->engine;
descriptor = allocation->descriptor;
MALI_DEBUG_ASSERT_POINTER( engine );
MALI_DEBUG_ASSERT_POINTER( descriptor );
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
{
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
return;
}
MALI_DEBUG_PRINT(6, ("Releasing %d os pages\n", allocation->num_pages));
MALI_DEBUG_ASSERT( allocation->num_pages <= info->num_pages_allocated);
info->num_pages_allocated -= allocation->num_pages;
mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*allocation->num_pages, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
_mali_osk_free(allocation);
}
static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block)
{
const int allocation_order = 6; /* _MALI_OSK_CPU_PAGE_SIZE << 6 */
void *virt;
const u32 pages_to_allocate = 1 << allocation_order;
const u32 size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order;
os_allocator * info;
u32 cpu_phys_base;
MALI_DEBUG_ASSERT_POINTER(ctx);
info = (os_allocator*)ctx;
/* Ensure we don't allocate more than we're supposed to from the ctx */
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
if ( (info->num_pages_allocated + pages_to_allocate > info->num_pages_max) && _mali_osk_mem_check_allocated(info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE) )
{
/* return OOM */
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return MALI_MEM_ALLOC_NONE;
}
virt = _mali_osk_mem_allocioregion( &cpu_phys_base, size );
if ( NULL == virt )
{
/* return OOM */
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return MALI_MEM_ALLOC_NONE;
}
block->release = os_allocator_page_table_block_release;
block->ctx = ctx;
block->handle = (void*)allocation_order;
block->size = size;
block->phys_base = cpu_phys_base - info->cpu_usage_adjust;
block->mapping = virt;
info->num_pages_allocated += pages_to_allocate;
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
return MALI_MEM_ALLOC_FINISHED;
}
static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block )
{
os_allocator * info;
u32 allocation_order;
u32 pages_allocated;
MALI_DEBUG_ASSERT_POINTER( page_table_block );
info = (os_allocator*)page_table_block->ctx;
MALI_DEBUG_ASSERT_POINTER( info );
allocation_order = (u32)page_table_block->handle;
pages_allocated = 1 << allocation_order;
MALI_DEBUG_ASSERT( pages_allocated * _MALI_OSK_CPU_PAGE_SIZE == page_table_block->size );
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
{
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
return;
}
MALI_DEBUG_ASSERT( pages_allocated <= info->num_pages_allocated);
info->num_pages_allocated -= pages_allocated;
/* Adjust phys_base from mali physical address to CPU physical address */
_mali_osk_mem_freeioregion( page_table_block->phys_base + info->cpu_usage_adjust, page_table_block->size, page_table_block->mapping );
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_MEM_OS_H__
#define __MALI_KERNEL_MEM_OS_H__
/**
* @brief Creates an object that manages allocating OS memory
*
* Creates an object that provides an interface to allocate OS memory and
* have it mapped into the Mali virtual memory space.
*
* The object exposes pointers to
* - allocate OS memory
* - allocate Mali page tables in OS memory
* - destroy the object
*
* Allocations from OS memory are of type mali_physical_memory_allocation
* which provides a function to release the allocation.
*
* @param max_allocation max. number of bytes that can be allocated from OS memory
* @param cpu_usage_adjust value to add to mali physical addresses to obtain CPU physical addresses
* @param name description of the allocator
* @return pointer to mali_physical_memory_allocator object. NULL on failure.
**/
mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u32 cpu_usage_adjust, const char *name);
#endif /* __MALI_KERNEL_MEM_OS_H__ */

View File

@@ -0,0 +1,348 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_kernel_core.h"
#include "mali_kernel_memory_engine.h"
#include "mali_osk.h"
#include "mali_osk_list.h"
typedef struct memory_engine
{
mali_kernel_mem_address_manager * mali_address;
mali_kernel_mem_address_manager * process_address;
} memory_engine;
mali_allocation_engine mali_allocation_engine_create(mali_kernel_mem_address_manager * mali_address_manager, mali_kernel_mem_address_manager * process_address_manager)
{
memory_engine * engine;
/* Mali Address Manager need not support unmap_physical */
MALI_DEBUG_ASSERT_POINTER(mali_address_manager);
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->allocate);
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->release);
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->map_physical);
/* Process Address Manager must support unmap_physical for OS allocation
* error path handling */
MALI_DEBUG_ASSERT_POINTER(process_address_manager);
MALI_DEBUG_ASSERT_POINTER(process_address_manager->allocate);
MALI_DEBUG_ASSERT_POINTER(process_address_manager->release);
MALI_DEBUG_ASSERT_POINTER(process_address_manager->map_physical);
MALI_DEBUG_ASSERT_POINTER(process_address_manager->unmap_physical);
engine = (memory_engine*)_mali_osk_malloc(sizeof(memory_engine));
if (NULL == engine) return NULL;
engine->mali_address = mali_address_manager;
engine->process_address = process_address_manager;
return (mali_allocation_engine)engine;
}
void mali_allocation_engine_destroy(mali_allocation_engine engine)
{
MALI_DEBUG_ASSERT_POINTER(engine);
_mali_osk_free(engine);
}
_mali_osk_errcode_t mali_allocation_engine_allocate_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_allocators, _mali_osk_list_t *tracking_list )
{
memory_engine * engine = (memory_engine*)mem_engine;
MALI_DEBUG_ASSERT_POINTER(engine);
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_ASSERT_POINTER(physical_allocators);
/* ASSERT that the list member has been initialized, even if it won't be
* used for tracking. We need it to be initialized to see if we need to
* delete it from a list in the release function. */
MALI_DEBUG_ASSERT( NULL != descriptor->list.next && NULL != descriptor->list.prev );
if (_MALI_OSK_ERR_OK == engine->mali_address->allocate(descriptor))
{
_mali_osk_errcode_t res = _MALI_OSK_ERR_OK;
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
res = engine->process_address->allocate(descriptor);
}
if ( _MALI_OSK_ERR_OK == res )
{
/* address space setup OK, commit physical memory to the allocation */
mali_physical_memory_allocator * active_allocator = physical_allocators;
struct mali_physical_memory_allocation * active_allocation_tracker = &descriptor->physical_allocation;
u32 offset = 0;
while ( NULL != active_allocator )
{
switch (active_allocator->allocate(active_allocator->ctx, mem_engine, descriptor, &offset, active_allocation_tracker))
{
case MALI_MEM_ALLOC_FINISHED:
if ( NULL != tracking_list )
{
/* Insert into the memory session list */
/* ASSERT that it is not already part of a list */
MALI_DEBUG_ASSERT( _mali_osk_list_empty( &descriptor->list ) );
_mali_osk_list_add( &descriptor->list, tracking_list );
}
MALI_SUCCESS; /* all done */
case MALI_MEM_ALLOC_NONE:
/* reuse current active_allocation_tracker */
MALI_DEBUG_PRINT( 4, ("Memory Engine Allocate: No allocation on %s, resorting to %s\n",
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
active_allocator = active_allocator->next;
break;
case MALI_MEM_ALLOC_PARTIAL:
if (NULL != active_allocator->next)
{
/* need a new allocation tracker */
active_allocation_tracker->next = _mali_osk_calloc(1, sizeof(mali_physical_memory_allocation));
if (NULL != active_allocation_tracker->next)
{
active_allocation_tracker = active_allocation_tracker->next;
MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate: Partial allocation on %s, resorting to %s\n",
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
active_allocator = active_allocator->next;
break;
}
}
/* FALL THROUGH */
case MALI_MEM_ALLOC_INTERNAL_FAILURE:
active_allocator = NULL; /* end the while loop */
break;
}
}
MALI_DEBUG_PRINT(3, ("Non-fatal OOM, have to cleanup, stopped at offset %d for size %d\n", offset, descriptor->size));
/* allocation failure, start cleanup */
/* loop over any potential partial allocations */
active_allocation_tracker = &descriptor->physical_allocation;
while (NULL != active_allocation_tracker)
{
/* handle blank trackers which will show up during failure */
if (NULL != active_allocation_tracker->release)
{
active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
}
active_allocation_tracker = active_allocation_tracker->next;
}
/* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
{
void * buf = active_allocation_tracker;
active_allocation_tracker = active_allocation_tracker->next;
_mali_osk_free(buf);
}
/* release the address spaces */
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
engine->process_address->release(descriptor);
}
}
engine->mali_address->release(descriptor);
}
MALI_ERROR(_MALI_OSK_ERR_FAULT);
}
void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor)
{
memory_engine * engine = (memory_engine*)mem_engine;
mali_physical_memory_allocation * active_allocation_tracker;
MALI_DEBUG_ASSERT_POINTER(engine);
MALI_DEBUG_ASSERT_POINTER(descriptor);
/* Determine whether we need to remove this from a tracking list */
if ( ! _mali_osk_list_empty( &descriptor->list ) )
{
_mali_osk_list_del( &descriptor->list );
/* Clear the list for debug mode, catch use-after-free */
MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; )
}
engine->mali_address->release(descriptor);
active_allocation_tracker = &descriptor->physical_allocation;
while (NULL != active_allocation_tracker)
{
MALI_DEBUG_ASSERT_POINTER(active_allocation_tracker->release);
active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
active_allocation_tracker = active_allocation_tracker->next;
}
/* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
{
void * buf = active_allocation_tracker;
active_allocation_tracker = active_allocation_tracker->next;
_mali_osk_free(buf);
}
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
engine->process_address->release(descriptor);
}
}
_mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size)
{
_mali_osk_errcode_t err;
memory_engine * engine = (memory_engine*)mem_engine;
_mali_osk_mem_mapregion_flags_t unmap_flags = (_mali_osk_mem_mapregion_flags_t)0;
MALI_DEBUG_ASSERT_POINTER(engine);
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X\n", phys, size, offset));
MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
MALI_DEBUG_ASSERT_POINTER(engine->mali_address->map_physical);
/* Handle process address manager first, because we may need them to
* allocate the physical page */
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
/* Handle OS-allocated specially, since an adjustment may be required */
if ( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC == phys )
{
MALI_DEBUG_ASSERT( _MALI_OSK_CPU_PAGE_SIZE == size );
/* Set flags to use on error path */
unmap_flags |= _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR;
err = engine->process_address->map_physical(descriptor, offset, &phys, size);
/* Adjust for cpu physical address to mali physical address */
phys -= cpu_usage_adjust;
}
else
{
u32 cpu_phys;
/* Adjust mali physical address to cpu physical address */
cpu_phys = phys + cpu_usage_adjust;
err = engine->process_address->map_physical(descriptor, offset, &cpu_phys, size);
}
if ( _MALI_OSK_ERR_OK != err )
{
MALI_ERROR( err );
}
}
MALI_DEBUG_PRINT(4, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset));
/* Mali address manager must use the physical address - no point in asking
* it to allocate another one for us */
MALI_DEBUG_ASSERT( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC != phys );
err = engine->mali_address->map_physical(descriptor, offset, &phys, size);
if ( _MALI_OSK_ERR_OK != err )
{
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
MALI_DEBUG_PRINT( 2, ("Process address manager succeeded, but Mali Address manager failed for phys=0x%08X size=0x%08X, offset=0x%08X. Will unmap.\n", phys, size, offset));
engine->process_address->unmap_physical(descriptor, offset, size, unmap_flags);
}
MALI_ERROR( err );
}
MALI_SUCCESS;
}
void mali_allocation_engine_unmap_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t unmap_flags )
{
memory_engine * engine = (memory_engine*)mem_engine;
MALI_DEBUG_ASSERT_POINTER(engine);
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_PRINT(7, ("UnMapping length 0x%08X at offset 0x%08X\n", size, offset));
MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
MALI_DEBUG_ASSERT_POINTER(engine->process_address);
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
{
/* Mandetory for process_address manager to have an unmap function*/
engine->process_address->unmap_physical( descriptor, offset, size, unmap_flags );
}
/* Optional for mali_address manager to have an unmap function*/
if ( NULL != engine->mali_address->unmap_physical )
{
engine->mali_address->unmap_physical( descriptor, offset, size, unmap_flags );
}
}
_mali_osk_errcode_t mali_allocation_engine_allocate_page_tables(mali_allocation_engine engine, mali_page_table_block * descriptor, mali_physical_memory_allocator * physical_provider)
{
mali_physical_memory_allocator * active_allocator = physical_provider;
MALI_DEBUG_ASSERT_POINTER(descriptor);
MALI_DEBUG_ASSERT_POINTER(physical_provider);
while ( NULL != active_allocator )
{
switch (active_allocator->allocate_page_table_block(active_allocator->ctx, descriptor))
{
case MALI_MEM_ALLOC_FINISHED:
MALI_SUCCESS; /* all done */
case MALI_MEM_ALLOC_NONE:
/* try next */
MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate PageTables: No allocation on %s, resorting to %s\n",
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
active_allocator = active_allocator->next;
break;
case MALI_MEM_ALLOC_PARTIAL:
MALI_DEBUG_PRINT(1, ("Invalid return value from allocate_page_table_block call: MALI_MEM_ALLOC_PARTIAL\n"));
/* FALL THROUGH */
case MALI_MEM_ALLOC_INTERNAL_FAILURE:
MALI_DEBUG_PRINT(1, ("Aborting due to allocation failure\n"));
active_allocator = NULL; /* end the while loop */
break;
}
}
MALI_ERROR(_MALI_OSK_ERR_FAULT);
}
void mali_allocation_engine_report_allocators( mali_physical_memory_allocator * physical_provider )
{
mali_physical_memory_allocator * active_allocator = physical_provider;
MALI_DEBUG_ASSERT_POINTER(physical_provider);
MALI_DEBUG_PRINT( 1, ("Mali memory allocators will be used in this order of preference (lowest numbered first) :\n"));
while ( NULL != active_allocator )
{
if ( NULL != active_allocator->name )
{
MALI_DEBUG_PRINT( 1, ("\t%d: %s\n", active_allocator->alloc_order, active_allocator->name) );
}
else
{
MALI_DEBUG_PRINT( 1, ("\t%d: (UNNAMED ALLOCATOR)\n", active_allocator->alloc_order) );
}
active_allocator = active_allocator->next;
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_MEMORY_ENGINE_H__
#define __MALI_KERNEL_MEMORY_ENGINE_H__
typedef void * mali_allocation_engine;
typedef enum { MALI_MEM_ALLOC_FINISHED, MALI_MEM_ALLOC_PARTIAL, MALI_MEM_ALLOC_NONE, MALI_MEM_ALLOC_INTERNAL_FAILURE } mali_physical_memory_allocation_result;
typedef struct mali_physical_memory_allocation
{
void (*release)(void * ctx, void * handle); /**< Function to call on to release the physical memory */
void * ctx;
void * handle;
struct mali_physical_memory_allocation * next;
} mali_physical_memory_allocation;
struct mali_page_table_block;
typedef struct mali_page_table_block
{
void (*release)(struct mali_page_table_block *page_table_block);
void * ctx;
void * handle;
u32 size; /**< In bytes, should be a multiple of MALI_MMU_PAGE_SIZE to avoid internal fragementation */
u32 phys_base; /**< Mali physical address */
mali_io_address mapping;
} mali_page_table_block;
/** @addtogroup _mali_osk_low_level_memory
* @{ */
typedef enum
{
MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE = 0x1,
MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE = 0x2,
} mali_memory_allocation_flag;
/**
* Supplying this 'magic' physical address requests that the OS allocate the
* physical address at page commit time, rather than commiting a specific page
*/
#define MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC ((u32)(-1))
typedef struct mali_memory_allocation
{
/* Information about the allocation */
void * mapping; /**< CPU virtual address where the memory is mapped at */
u32 mali_address; /**< The Mali seen address of the memory allocation */
u32 size; /**< Size of the allocation */
u32 permission; /**< Permission settings */
mali_memory_allocation_flag flags;
_mali_osk_lock_t * lock;
/* Manager specific information pointers */
void * mali_addr_mapping_info; /**< Mali address allocation specific info */
void * process_addr_mapping_info; /**< Mapping manager specific info */
mali_physical_memory_allocation physical_allocation;
_mali_osk_list_t list; /**< List for linking together memory allocations into the session's memory head */
} mali_memory_allocation;
/** @} */ /* end group _mali_osk_low_level_memory */
typedef struct mali_physical_memory_allocator
{
mali_physical_memory_allocation_result (*allocate)(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
mali_physical_memory_allocation_result (*allocate_page_table_block)(void * ctx, mali_page_table_block * block); /* MALI_MEM_ALLOC_PARTIAL not allowed */
void (*destroy)(struct mali_physical_memory_allocator * allocator);
void * ctx;
const char * name; /**< Descriptive name for use in mali_allocation_engine_report_allocators, or NULL */
u32 alloc_order; /**< Order in which the allocations should happen */
struct mali_physical_memory_allocator * next;
} mali_physical_memory_allocator;
typedef struct mali_kernel_mem_address_manager
{
_mali_osk_errcode_t (*allocate)(mali_memory_allocation *); /**< Function to call to reserve an address */
void (*release)(mali_memory_allocation *); /**< Function to call to free the address allocated */
/**
* Function called for each physical sub allocation.
* Called for each physical block allocated by the physical memory manager.
* @param[in] descriptor The memory descriptor in question
* @param[in] off Offset from the start of range
* @param[in,out] phys_addr A pointer to the physical address of the start of the
* physical block. When *phys_addr == MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC
* is used, this requests the function must allocate the physical page
* itself, and return it through the pointer provided.
* @param[in] size Length in bytes of the physical block
* @return _MALI_OSK_ERR_OK on success.
* A value of type _mali_osk_errcode_t other than _MALI_OSK_ERR_OK indicates failure.
* Specifically, _MALI_OSK_ERR_UNSUPPORTED indicates that the function
* does not support allocating physical pages itself.
*/
_mali_osk_errcode_t (*map_physical)(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size);
/**
* Function called to remove a physical sub allocation.
* Called on error paths where one of the address managers fails.
*
* @note this is optional. For address managers where this is not
* implemented, the value of this member is NULL. The memory engine
* currently does not require the mali address manager to be able to
* unmap individual pages, but the process address manager must have this
* capability.
*
* @param[in] descriptor The memory descriptor in question
* @param[in] off Offset from the start of range
* @param[in] size Length in bytes of the physical block
* @param[in] flags flags to use on a per-page basis. For OS-allocated
* physical pages, this must include _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR.
* @return _MALI_OSK_ERR_OK on success.
* A value of type _mali_osk_errcode_t other than _MALI_OSK_ERR_OK indicates failure.
*/
void (*unmap_physical)(mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t flags);
} mali_kernel_mem_address_manager;
mali_allocation_engine mali_allocation_engine_create(mali_kernel_mem_address_manager * mali_address_manager, mali_kernel_mem_address_manager * process_address_manager);
void mali_allocation_engine_destroy(mali_allocation_engine engine);
int mali_allocation_engine_allocate_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_provider, _mali_osk_list_t *tracking_list );
void mali_allocation_engine_release_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor);
int mali_allocation_engine_map_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size);
void mali_allocation_engine_unmap_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t unmap_flags);
int mali_allocation_engine_allocate_page_tables(mali_allocation_engine, mali_page_table_block * descriptor, mali_physical_memory_allocator * physical_provider);
void mali_allocation_engine_report_allocators(mali_physical_memory_allocator * physical_provider);
#endif /* __MALI_KERNEL_MEMORY_ENGINE_H__ */

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_PP_H__
#define __MALI_KERNEL_PP_H__
extern struct mali_kernel_subsystem mali_subsystem_mali200;
#if USING_MALI_PMM
_mali_osk_errcode_t malipp_signal_power_up( u32 core_num, mali_bool queue_only );
_mali_osk_errcode_t malipp_signal_power_down( u32 core_num, mali_bool immediate_only );
#endif
#endif /* __MALI_KERNEL_PP_H__ */

View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_osk_mali.h"
#include "mali_ukk.h"
#include "mali_timestamp.h"
#define MALI_PROFILING_MAX_BUFFER_ENTRIES 1048576
typedef struct mali_profiling_entry
{
u64 timestamp;
u32 event_id;
u32 data[5];
} mali_profiling_entry;
typedef enum mali_profiling_state
{
MALI_PROFILING_STATE_UNINITIALIZED,
MALI_PROFILING_STATE_IDLE,
MALI_PROFILING_STATE_RUNNING,
MALI_PROFILING_STATE_RETURN,
} mali_profiling_state;
static _mali_osk_lock_t *lock = NULL;
static mali_profiling_state prof_state = MALI_PROFILING_STATE_UNINITIALIZED;
static mali_profiling_entry* profile_entries = NULL;
static u32 profile_entry_count = 0;
static _mali_osk_atomic_t profile_insert_index;
static _mali_osk_atomic_t profile_entries_written;
_mali_osk_errcode_t _mali_profiling_init(void)
{
profile_entries = NULL;
profile_entry_count = 0;
_mali_osk_atomic_init(&profile_insert_index, 0);
_mali_osk_atomic_init(&profile_entries_written, 0);
lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 );
if (NULL == lock)
{
return _MALI_OSK_ERR_FAULT;
}
prof_state = MALI_PROFILING_STATE_IDLE;
return _MALI_OSK_ERR_OK;
}
void _mali_profiling_term(void)
{
prof_state = MALI_PROFILING_STATE_UNINITIALIZED;
/* wait for all elements to be completely inserted into array */
while (_mali_osk_atomic_read(&profile_insert_index) != _mali_osk_atomic_read(&profile_entries_written))
{
/* do nothing */;
}
if (NULL != profile_entries)
{
_mali_osk_free(profile_entries);
profile_entries = NULL;
}
if (NULL != lock)
{
_mali_osk_lock_term(lock);
lock = NULL;
}
}
inline _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4)
{
u32 cur_index = _mali_osk_atomic_inc_return(&profile_insert_index) - 1;
if (prof_state != MALI_PROFILING_STATE_RUNNING || cur_index >= profile_entry_count)
{
/*
* Not in recording mode, or buffer is full
* Decrement index again, and early out
*/
_mali_osk_atomic_dec(&profile_insert_index);
return _MALI_OSK_ERR_FAULT;
}
profile_entries[cur_index].timestamp = _mali_timestamp_get();
profile_entries[cur_index].event_id = event_id;
profile_entries[cur_index].data[0] = data0;
profile_entries[cur_index].data[1] = data1;
profile_entries[cur_index].data[2] = data2;
profile_entries[cur_index].data[3] = data3;
profile_entries[cur_index].data[4] = data4;
_mali_osk_atomic_inc(&profile_entries_written);
return _MALI_OSK_ERR_OK;
}
_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args)
{
_mali_osk_errcode_t ret;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (prof_state != MALI_PROFILING_STATE_IDLE)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
}
if (args->limit > MALI_PROFILING_MAX_BUFFER_ENTRIES)
{
args->limit = MALI_PROFILING_MAX_BUFFER_ENTRIES;
}
profile_entries = _mali_osk_malloc(args->limit * sizeof(mali_profiling_entry));
profile_entry_count = args->limit;
if (NULL == profile_entries)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_NOMEM;
}
ret = _mali_timestamp_reset();
if (ret == _MALI_OSK_ERR_OK)
{
prof_state = MALI_PROFILING_STATE_RUNNING;
}
else
{
_mali_osk_free(profile_entries);
profile_entries = NULL;
}
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return ret;
}
_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args)
{
/* Always add process and thread identificator in the first two data elements for events from user space */
return _mali_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]);
}
_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args)
{
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (prof_state != MALI_PROFILING_STATE_RUNNING)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
}
/* go into return state (user to retreive events), no more events will be added after this */
prof_state = MALI_PROFILING_STATE_RETURN;
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
/* wait for all elements to be completely inserted into array */
while (_mali_osk_atomic_read(&profile_insert_index) != _mali_osk_atomic_read(&profile_entries_written))
{
/* do nothing */;
}
args->count = _mali_osk_atomic_read(&profile_insert_index);
return _MALI_OSK_ERR_OK;
}
_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args)
{
u32 index = args->index;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (prof_state != MALI_PROFILING_STATE_RETURN)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
}
if (index >= _mali_osk_atomic_read(&profile_entries_written))
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_FAULT;
}
args->timestamp = profile_entries[index].timestamp;
args->event_id = profile_entries[index].event_id;
args->data[0] = profile_entries[index].data[0];
args->data[1] = profile_entries[index].data[1];
args->data[2] = profile_entries[index].data[2];
args->data[3] = profile_entries[index].data[3];
args->data[4] = profile_entries[index].data[4];
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_OK;
}
_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args)
{
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (prof_state != MALI_PROFILING_STATE_RETURN)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
}
prof_state = MALI_PROFILING_STATE_IDLE;
profile_entry_count = 0;
_mali_osk_atomic_init(&profile_insert_index, 0);
_mali_osk_atomic_init(&profile_entries_written, 0);
if (NULL != profile_entries)
{
_mali_osk_free(profile_entries);
profile_entries = NULL;
}
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return _MALI_OSK_ERR_OK;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_PROFILING_H__
#define __MALI_KERNEL_PROFILING_H__
#if MALI_TIMELINE_PROFILING_ENABLED
#include <../../../include/cinstr/mali_cinstr_profiling_events_m200.h>
/**
* Initialize the profiling module.
* @return _MALI_OSK_ERR_OK on success, otherwise failure.
*/
_mali_osk_errcode_t _mali_profiling_init(void);
/*
* Terminate the profiling module.
*/
void _mali_profiling_term(void);
/**
* Add an profiling event
*
* @param event_id The event identificator.
* @param data0 - First data parameter, depending on event_id specified.
* @param data1 - Second data parameter, depending on event_id specified.
* @param data2 - Third data parameter, depending on event_id specified.
* @param data3 - Fourth data parameter, depending on event_id specified.
* @param data4 - Fifth data parameter, depending on event_id specified.
* @return _MALI_OSK_ERR_OK on success, otherwise failure.
*/
_mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4);
#endif /* MALI_TIMELINE_PROFILING_ENABLED */
#endif /* __MALI_KERNEL_PROFILING_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,363 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_RENDERCORE_H__
#define __MALI_RENDERCORE_H__
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_subsystem.h"
#define PRIORITY_LEVELS 3
#define PRIORITY_MAX 0
#define PRIORITY_MIN (PRIORITY_MAX+PRIORITY_LEVELS-1)
/* This file contains what we need in kernel for all core types. */
typedef enum
{
CORE_IDLE, /**< Core is ready for a new job */
CORE_WORKING, /**< Core is working on a job */
CORE_WATCHDOG_TIMEOUT, /**< Core is working but it has timed out */
CORE_POLL, /**< Poll timer triggered, pending handling */
CORE_HANG_CHECK_TIMEOUT,/**< Timeout for hang detection */
CORE_OFF /**< Core is powered off */
} mali_core_status;
typedef enum
{
SUBSYSTEM_RESCHEDULE,
SUBSYSTEM_WAIT
} mali_subsystem_reschedule_option;
typedef enum
{
MALI_CORE_RESET_STYLE_RUNABLE,
MALI_CORE_RESET_STYLE_DISABLE,
MALI_CORE_RESET_STYLE_HARD
} mali_core_reset_style;
typedef enum
{
JOB_STATUS_CONTINUE_RUN = 0x01,
JOB_STATUS_END_SUCCESS = 1<<(16+0),
JOB_STATUS_END_OOM = 1<<(16+1),
JOB_STATUS_END_ABORT = 1<<(16+2),
JOB_STATUS_END_TIMEOUT_SW = 1<<(16+3),
JOB_STATUS_END_HANG = 1<<(16+4),
JOB_STATUS_END_SEG_FAULT = 1<<(16+5),
JOB_STATUS_END_ILLEGAL_JOB = 1<<(16+6),
JOB_STATUS_END_UNKNOWN_ERR = 1<<(16+7),
JOB_STATUS_END_SHUTDOWN = 1<<(16+8),
JOB_STATUS_END_SYSTEM_UNUSABLE = 1<<(16+9)
} mali_subsystem_job_end_code;
struct mali_core_job;
struct mali_core_subsystem;
struct mali_core_renderunit;
struct mali_core_session;
/* We have one of these subsystems for each core type */
typedef struct mali_core_subsystem
{
struct mali_core_renderunit ** mali_core_array; /* An array of all cores of this type */
u32 number_of_cores; /* Number of cores in this list */
_mali_core_type core_type;
u32 magic_nr;
_mali_osk_list_t renderunit_idle_head; /* Idle cores of this type */
_mali_osk_list_t renderunit_off_head; /* Powered off cores of this type */
/* Linked list for each priority of sessions with a job ready for scheduelling */
_mali_osk_list_t awaiting_sessions_head[PRIORITY_LEVELS];
u32 awaiting_sessions_sum_all_priorities;
/* Linked list of all sessions connected to this coretype */
_mali_osk_list_t all_sessions_head;
/* Linked list of all sessions connected to this coretype */
struct _mali_osk_notification_queue_t * notification_queue;
const char * name;
mali_kernel_subsystem_identifier id;
/**** Functions registered for this core type. Set during mali_core_init ******/
/* Start this job on this core. Return MALI_TRUE if the job was started. */
_mali_osk_errcode_t (*start_job)(struct mali_core_job * job, struct mali_core_renderunit * core);
/* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */
u32 (*irq_handler_upper_half)(struct mali_core_renderunit * core);
/* This function should check if the interrupt indicates that job was finished.
If so it should update the job-struct, reset the core registers, and return MALI_TRUE, .
If the job is still working after this function it should return MALI_FALSE.
The function must also enable the bits in the interrupt mask for the core.
Called by the bottom half interrupt function. */
int (*irq_handler_bottom_half)(struct mali_core_renderunit* core);
/* This function is called from the ioctl function and should return a mali_core_job pointer
to a created mali_core_job object with the data given from userspace */
_mali_osk_errcode_t (*get_new_job_from_user)(struct mali_core_session * session, void * argument);
_mali_osk_errcode_t (*suspend_response)(struct mali_core_session * session, void * argument);
/* This function is called from the ioctl function and should write the necessary data
to userspace telling which job was finished and the status and debuginfo for this job.
The function must also free and cleanup the input job object. */
void (*return_job_to_user)(struct mali_core_job * job, mali_subsystem_job_end_code end_status);
/* Is called when a subsystem shuts down. This function needs to
release internal pointers in the core struct, and free the
core struct before returning.
It is not allowed to write to any registers, since this
unmapping is already done. */
void (*renderunit_delete)(struct mali_core_renderunit * core);
/* Is called when we want to abort a job that is running on the core.
This is done if program exits while core is running */
void (*reset_core)(struct mali_core_renderunit * core, mali_core_reset_style style);
/* Is called when the rendercore wants the core to give an interrupt */
void (*probe_core_irq_trigger)(struct mali_core_renderunit* core);
/* Is called when the irq probe wants the core to acknowledge an interrupt from the hw */
_mali_osk_errcode_t (*probe_core_irq_acknowledge)(struct mali_core_renderunit* core);
/* Called when the rendercore want to issue a bus stop request to a core */
void (*stop_bus)(struct mali_core_renderunit* core);
} mali_core_subsystem;
/* Per core data. This must be embedded into each core type internal core info. */
typedef struct mali_core_renderunit
{
struct mali_core_subsystem * subsystem; /* The core belongs to this subsystem */
_mali_osk_list_t list; /* Is always in subsystem->idle_list OR session->renderunits_working */
mali_core_status state;
mali_bool error_recovery; /* Indicates if the core is waiting for external help to recover (typically the MMU) */
mali_bool in_detach_function;
struct mali_core_job * current_job; /* Current job being processed on this core ||NULL */
u32 magic_nr;
_mali_osk_timer_t * timer;
_mali_osk_timer_t * timer_hang_detection;
mali_io_address registers_mapped; /* IO-mapped pointer to registers */
u32 registers_base_addr; /* Base addres of the registers */
u32 size; /* The size of registers_mapped */
const char * description; /* Description of this core. */
u32 irq_nr; /* The IRQ nr for this core */
u32 core_version;
#if USING_MMU
u32 mmu_id;
void * mmu; /* The MMU this rendercore is behind.*/
#endif
#if USING_MALI_PMM
mali_pmm_core_id pmm_id; /* The PMM core id */
mali_bool pend_power_down; /* Power down is requested */
#endif
u32 core_number; /* 0 for first detected core of this type, 1 for second and so on */
_mali_osk_irq_t *irq;
} mali_core_renderunit;
/* Per open FILE data. */
/* You must held subsystem->mutex before any transactions to this datatype. */
typedef struct mali_core_session
{
struct mali_core_subsystem * subsystem; /* The session belongs to this subsystem */
_mali_osk_list_t renderunits_working_head; /* List of renderunits working for this session */
struct mali_core_job *job_waiting_to_run; /* The next job from this session to run */
_mali_osk_list_t awaiting_sessions_list; /* Linked list of sessions with jobs, for each priority */
_mali_osk_list_t all_sessions_list; /* Linked list of all sessions on the system. */
_mali_osk_notification_queue_t * notification_queue; /* Messages back to Base in userspace*/
#if USING_MMU
struct mali_session_data * mmu_session; /* The session associated with the MMU page tables for this core */
#endif
u32 magic_nr;
#if MALI_STATE_TRACKING
_mali_osk_atomic_t jobs_received;
_mali_osk_atomic_t jobs_started;
_mali_osk_atomic_t jobs_ended;
_mali_osk_atomic_t jobs_returned;
u32 pid;
#endif
} mali_core_session;
/* This must be embedded into a specific mali_core_job struct */
/* use this macro to get spesific mali_core_job: container_of(ptr, type, member)*/
typedef struct mali_core_job
{
_mali_osk_list_t list; /* Linked list of jobs. Used by struct mali_core_session */
struct mali_core_session *session;
u32 magic_nr;
u32 priority;
u32 watchdog_msecs;
u32 render_time_msecs ;
u32 start_time_jiffies;
unsigned long watchdog_jiffies;
u32 abort_id;
u32 job_nr;
} mali_core_job;
/*
* The rendercode subsystem is included in the subsystems[] array.
*/
extern struct mali_kernel_subsystem mali_subsystem_rendercore;
void subsystem_flush_mapped_mem_cache(void);
#define SUBSYSTEM_MAGIC_NR 0xdeadbeef
#define CORE_MAGIC_NR 0xcafebabe
#define SESSION_MAGIC_NR 0xbabe1234
#define JOB_MAGIC_NR 0x0123abcd
#define MALI_CHECK_SUBSYSTEM(subsystem)\
do { \
if ( SUBSYSTEM_MAGIC_NR != subsystem->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)
#define MALI_CHECK_CORE(CORE)\
do { \
if ( CORE_MAGIC_NR != CORE->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)
#define MALI_CHECK_SESSION(SESSION)\
do { \
if ( SESSION_MAGIC_NR != SESSION->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)
#define MALI_CHECK_JOB(JOB)\
do { \
if ( JOB_MAGIC_NR != JOB->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)
/* Check if job_a has higher priority than job_b */
MALI_STATIC_INLINE int job_has_higher_priority(mali_core_job * job_a, mali_core_job * job_b)
{
/* The lowest number has the highest priority */
return (int) (job_a->priority < job_b->priority);
}
MALI_STATIC_INLINE void job_priority_set(mali_core_job * job, u32 priority)
{
if (priority > PRIORITY_MIN) job->priority = PRIORITY_MIN;
else job->priority = priority;
}
void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs);
/* For use by const default register settings (e.g. set these after reset) */
typedef struct register_address_and_value
{
u32 address;
u32 value;
} register_address_and_value ;
/* For use by dynamic default register settings (e.g. set these after reset) */
typedef struct register_address_and_value_list
{
_mali_osk_list_t list;
register_address_and_value item;
} register_address_and_value_list ;
/* Used if the user wants to set a continious block of registers */
typedef struct register_array_user
{
u32 entries_in_array;
u32 start_address;
void __user * reg_array;
}register_array_user;
#define MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys) \
do { \
MALI_DEBUG_PRINT(5, ("MUTEX: GRAB %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
_mali_osk_lock_wait( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \
MALI_DEBUG_PRINT(5, ("MUTEX: GRABBED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
rendercores_global_mutex_is_held = 1; \
rendercores_global_mutex_owner = _mali_osk_get_tid(); \
} while (0) ;
#define MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys) \
do { \
MALI_DEBUG_PRINT(5, ("MUTEX: RELEASE %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
rendercores_global_mutex_is_held = 0; \
rendercores_global_mutex_owner = 0; \
if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
_mali_osk_lock_signal( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \
MALI_DEBUG_PRINT(5, ("MUTEX: RELEASED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0) ;
#define MALI_ASSERT_MUTEX_IS_GRABBED(input_pointer)\
do { \
if ( 0 == rendercores_global_mutex_is_held ) MALI_PRINT_ERROR(("ASSERT MUTEX SHOULD BE GRABBED"));\
if ( SUBSYSTEM_MAGIC_NR != input_pointer->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
if ( rendercores_global_mutex_owner != _mali_osk_get_tid() ) MALI_PRINT_ERROR(("Owner mismatch"));\
} while (0)
u32 mali_core_renderunit_register_read(struct mali_core_renderunit *core, u32 relative_address);
void mali_core_renderunit_register_read_array(struct mali_core_renderunit *core, u32 relative_address, u32 * result_array, u32 nr_of_regs);
void mali_core_renderunit_register_write(struct mali_core_renderunit *core, u32 relative_address, u32 new_val);
void mali_core_renderunit_register_write_array(struct mali_core_renderunit *core, u32 relative_address, u32 * write_array, u32 nr_of_regs);
_mali_osk_errcode_t mali_core_renderunit_init(struct mali_core_renderunit * core);
void mali_core_renderunit_term(struct mali_core_renderunit * core);
int mali_core_renderunit_map_registers(struct mali_core_renderunit *core);
void mali_core_renderunit_unmap_registers(struct mali_core_renderunit *core);
int mali_core_renderunit_irq_handler_add(struct mali_core_renderunit *core);
mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr);
int mali_core_subsystem_init(struct mali_core_subsystem * new_subsys);
#if USING_MMU
void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys);
#endif
int mali_core_subsystem_register_renderunit(struct mali_core_subsystem * subsys, struct mali_core_renderunit * core);
int mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info);
void mali_core_subsystem_cleanup(struct mali_core_subsystem * subsys);
#if USING_MMU
void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data);
#endif
void mali_core_session_begin(mali_core_session *session);
void mali_core_session_close(mali_core_session * session);
int mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return);
u32 mali_core_hang_check_timeout_get(void);
_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data);
_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores);
_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version);
_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void* argument);
void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id);
#if USING_MALI_PMM
_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only);
_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only);
#endif
#if MALI_STATE_TRACKING
u32 mali_core_renderunit_dump_state(mali_core_subsystem* subsystem, char *buf, u32 size);
#endif
#endif /* __MALI_RENDERCORE_H__ */

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_SESSION_MANAGER_H__
#define __MALI_KERNEL_SESSION_MANAGER_H__
/* Incomplete struct to pass around pointers to it */
struct mali_session_data;
void * mali_kernel_session_manager_slot_get(struct mali_session_data * session, int id);
#endif /* __MALI_KERNEL_SESSION_MANAGER_H__ */

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_kernel_subsystem.h
*/
#ifndef __MALI_KERNEL_SUBSYSTEM_H__
#define __MALI_KERNEL_SUBSYSTEM_H__
#include "mali_osk.h"
#include "mali_uk_types.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
/* typedefs of the datatypes used in the hook functions */
typedef void * mali_kernel_subsystem_session_slot;
typedef int mali_kernel_subsystem_identifier;
typedef _mali_osk_errcode_t (*mali_kernel_resource_registrator)(_mali_osk_resource_t *);
/**
* Broadcast notification messages
*/
typedef enum mali_core_notification_message
{
MMU_KILL_STEP0_LOCK_SUBSYSTEM, /**< Request to lock subsystem */
MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES, /**< Request to stop all buses */
MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS, /**< Request kill all jobs, and not start more jobs */
MMU_KILL_STEP3_CONTINUE_JOB_HANDLING, /**< Request to continue with new jobs on all cores */
MMU_KILL_STEP4_UNLOCK_SUBSYSTEM /**< Request to unlock subsystem */
} mali_core_notification_message;
/**
* A function pointer can be NULL if the subsystem isn't interested in the event.
*/
typedef struct mali_kernel_subsystem
{
/* subsystem control */
_mali_osk_errcode_t (*startup)(mali_kernel_subsystem_identifier id); /**< Called during module load or system startup*/
void (*shutdown)(mali_kernel_subsystem_identifier id); /**< Called during module unload or system shutdown */
/**
* Called during module load or system startup.
* Called when all subsystems have reported startup OK and all resources where successfully initialized
*/
_mali_osk_errcode_t (*load_complete)(mali_kernel_subsystem_identifier id);
/* per subsystem handlers */
_mali_osk_errcode_t (*system_info_fill)(_mali_system_info* info); /**< Fill info into info struct. MUST allocate memory with kmalloc, since it's kfree'd */
/* per session handlers */
/**
* Informs about a new session.
* slot can be used to track per-session per-subsystem data.
* queue can be used to send events to user space.
* _mali_osk_errcode_t error return value.
*/
_mali_osk_errcode_t (*session_begin)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue);
/**
* Informs that a session is ending
* slot was the same as given during session_begin
*/
void (*session_end)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot);
/* Used by subsystems to send messages to each other. This is the receiving end */
void (*broadcast_notification)(mali_core_notification_message message, u32 data);
#if MALI_STATE_TRACKING
/** Dump the current state of the subsystem */
u32 (*dump_state)(char *buf, u32 size);
#endif
} mali_kernel_subsystem;
/* functions used by the subsystems to interact with the core */
/**
* Register a resouce handler
* @param type The resoruce type to register a handler for
* @param handler Pointer to the function handling this resource
* @return _MALI_OSK_ERR_OK on success. Otherwise, a suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler);
/* function used to interact with other subsystems */
/**
* Broadcast a message
* Sends a message to all subsystems which have registered a broadcast notification handler
* @param message The message to send
* @param data Message specific extra data
*/
void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data);
#if MALI_STATE_TRACKING
/**
* Tell all subsystems to dump their current state
*/
u32 _mali_kernel_core_dump_state(char *buf, u32 size);
#endif
#endif /* __MALI_KERNEL_SUBSYSTEM_H__ */

View File

@@ -0,0 +1,207 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mali_kernel_utilization.h"
#include "mali_osk.h"
#include "mali_platform.h"
/* Define how often to calculate and report GPU utilization, in milliseconds */
#define MALI_GPU_UTILIZATION_TIMEOUT 1000
static _mali_osk_lock_t *time_data_lock;
static _mali_osk_atomic_t num_running_cores;
static u64 period_start_time = 0;
static u64 work_start_time = 0;
static u64 accumulated_work_time = 0;
static _mali_osk_timer_t *utilization_timer = NULL;
static mali_bool timer_running = MALI_FALSE;
static void calculate_gpu_utilization(void* arg)
{
u64 time_now;
u64 time_period;
u32 leading_zeroes;
u32 shift_val;
u32 work_normalized;
u32 period_normalized;
u32 utilization;
_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
if (accumulated_work_time == 0 && work_start_time == 0)
{
/* Don't reschedule timer, this will be started if new work arrives */
timer_running = MALI_FALSE;
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
/* No work done for this period, report zero usage */
mali_gpu_utilization_handler(0);
return;
}
time_now = _mali_osk_time_get_ns();
time_period = time_now - period_start_time;
/* If we are currently busy, update working period up to now */
if (work_start_time != 0)
{
accumulated_work_time += (time_now - work_start_time);
work_start_time = time_now;
}
/*
* We have two 64-bit values, a dividend and a divisor.
* To avoid dependencies to a 64-bit divider, we shift down the two values
* equally first.
* We shift the dividend up and possibly the divisor down, making the result X in 256.
*/
/* Shift the 64-bit values down so they fit inside a 32-bit integer */
leading_zeroes = _mali_osk_clz((u32)(time_period >> 32));
shift_val = 32 - leading_zeroes;
work_normalized = (u32)(accumulated_work_time >> shift_val);
period_normalized = (u32)(time_period >> shift_val);
/*
* Now, we should report the usage in parts of 256
* this means we must shift up the dividend or down the divisor by 8
* (we could do a combination, but we just use one for simplicity,
* but the end result should be good enough anyway)
*/
if (period_normalized > 0x00FFFFFF)
{
/* The divisor is so big that it is safe to shift it down */
period_normalized >>= 8;
}
else
{
/*
* The divisor is so small that we can shift up the dividend, without loosing any data.
* (dividend is always smaller than the divisor)
*/
work_normalized <<= 8;
}
utilization = work_normalized / period_normalized;
accumulated_work_time = 0;
period_start_time = time_now; /* starting a new period */
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
_mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT));
mali_gpu_utilization_handler(utilization);
}
_mali_osk_errcode_t mali_utilization_init(void)
{
time_data_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ|_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 );
if (NULL == time_data_lock)
{
return _MALI_OSK_ERR_FAULT;
}
_mali_osk_atomic_init(&num_running_cores, 0);
utilization_timer = _mali_osk_timer_init();
if (NULL == utilization_timer)
{
_mali_osk_lock_term(time_data_lock);
return _MALI_OSK_ERR_FAULT;
}
_mali_osk_timer_setcallback(utilization_timer, calculate_gpu_utilization, NULL);
return _MALI_OSK_ERR_OK;
}
void mali_utilization_suspend(void)
{
if (NULL != utilization_timer)
{
_mali_osk_timer_del(utilization_timer);
timer_running = MALI_FALSE;
}
}
void mali_utilization_term(void)
{
if (NULL != utilization_timer)
{
_mali_osk_timer_del(utilization_timer);
timer_running = MALI_FALSE;
_mali_osk_timer_term(utilization_timer);
utilization_timer = NULL;
}
_mali_osk_atomic_term(&num_running_cores);
_mali_osk_lock_term(time_data_lock);
}
void mali_utilization_core_start(void)
{
if (_mali_osk_atomic_inc_return(&num_running_cores) == 1)
{
/*
* We went from zero cores working, to one core working,
* we now consider the entire GPU for being busy
*/
_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
work_start_time = _mali_osk_time_get_ns();
if (timer_running != MALI_TRUE)
{
timer_running = MALI_TRUE;
period_start_time = work_start_time; /* starting a new period */
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
_mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT));
}
else
{
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
}
}
}
void mali_utilization_core_end(void)
{
if (_mali_osk_atomic_dec_return(&num_running_cores) == 0)
{
/*
* No more cores are working, so accumulate the time we was busy.
*/
u64 time_now;
_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
time_now = _mali_osk_time_get_ns();
accumulated_work_time += (time_now - work_start_time);
work_start_time = 0;
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_UTILIZATION_H__
#define __MALI_KERNEL_UTILIZATION_H__
#include "mali_osk.h"
/**
* Initialize/start the Mali GPU utilization metrics reporting.
*
* @return _MALI_OSK_ERR_OK on success, otherwise failure.
*/
_mali_osk_errcode_t mali_utilization_init(void);
/**
* Terminate the Mali GPU utilization metrics reporting
*/
void mali_utilization_term(void);
/**
* Should be called when a job is about to execute a job
*/
void mali_utilization_core_start(void);
/**
* Should be called to stop the utilization timer during system suspend
*/
void mali_utilization_suspend(void);
/**
* Should be called when a job has completed executing a job
*/
void mali_utilization_core_end(void);
#endif /* __MALI_KERNEL_UTILIZATION_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_bitops.h
* Implementation of the OS abstraction layer for the kernel device driver
*/
#ifndef __MALI_OSK_BITOPS_H__
#define __MALI_OSK_BITOPS_H__
#ifdef __cplusplus
extern "C"
{
#endif
MALI_STATIC_INLINE void _mali_internal_clear_bit( u32 bit, u32 *addr )
{
MALI_DEBUG_ASSERT( bit < 32 );
MALI_DEBUG_ASSERT( NULL != addr );
(*addr) &= ~(1 << bit);
}
MALI_STATIC_INLINE void _mali_internal_set_bit( u32 bit, u32 *addr )
{
MALI_DEBUG_ASSERT( bit < 32 );
MALI_DEBUG_ASSERT( NULL != addr );
(*addr) |= (1 << bit);
}
MALI_STATIC_INLINE u32 _mali_internal_test_bit( u32 bit, u32 value )
{
MALI_DEBUG_ASSERT( bit < 32 );
return value & (1 << bit);
}
MALI_STATIC_INLINE int _mali_internal_find_first_zero_bit( u32 value )
{
u32 inverted;
u32 negated;
u32 isolated;
u32 leading_zeros;
/* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range 0..31 */
inverted = ~value; /* zzz...z1000...0 */
/* Using count_trailing_zeros on inverted value -
* See ARM System Developers Guide for details of count_trailing_zeros */
/* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */
negated = (u32)-inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */
/* negated = xxx...x1000...0 */
isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */
/* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it
* Note that the output is zero if value was all 1s */
leading_zeros = _mali_osk_clz( isolated );
return 31 - leading_zeros;
}
/** @defgroup _mali_osk_bitops OSK Non-atomic Bit-operations
* @{ */
/**
* These bit-operations do not work atomically, and so locks must be used if
* atomicity is required.
*
* Reference implementations for Little Endian are provided, and so it should
* not normally be necessary to re-implement these. Efficient bit-twiddling
* techniques are used where possible, implemented in portable C.
*
* Note that these reference implementations rely on _mali_osk_clz() being
* implemented.
*/
/** @brief Clear a bit in a sequence of 32-bit words
* @param nr bit number to clear, starting from the (Little-endian) least
* significant bit
* @param addr starting point for counting.
*/
MALI_STATIC_INLINE void _mali_osk_clear_nonatomic_bit( u32 nr, u32 *addr )
{
addr += nr >> 5; /* find the correct word */
nr = nr & ((1 << 5)-1); /* The bit number within the word */
_mali_internal_clear_bit( nr, addr );
}
/** @brief Set a bit in a sequence of 32-bit words
* @param nr bit number to set, starting from the (Little-endian) least
* significant bit
* @param addr starting point for counting.
*/
MALI_STATIC_INLINE void _mali_osk_set_nonatomic_bit( u32 nr, u32 *addr )
{
addr += nr >> 5; /* find the correct word */
nr = nr & ((1 << 5)-1); /* The bit number within the word */
_mali_internal_set_bit( nr, addr );
}
/** @brief Test a bit in a sequence of 32-bit words
* @param nr bit number to test, starting from the (Little-endian) least
* significant bit
* @param addr starting point for counting.
* @return zero if bit was clear, non-zero if set. Do not rely on the return
* value being related to the actual word under test.
*/
MALI_STATIC_INLINE u32 _mali_osk_test_bit( u32 nr, u32 *addr )
{
addr += nr >> 5; /* find the correct word */
nr = nr & ((1 << 5)-1); /* The bit number within the word */
return _mali_internal_test_bit( nr, *addr );
}
/* Return maxbit if not found */
/** @brief Find the first zero bit in a sequence of 32-bit words
* @param addr starting point for search.
* @param maxbit the maximum number of bits to search
* @return the number of the first zero bit found, or maxbit if none were found
* in the specified range.
*/
MALI_STATIC_INLINE u32 _mali_osk_find_first_zero_bit( const u32 *addr, u32 maxbit )
{
u32 total;
for ( total = 0; total < maxbit; total += 32, ++addr )
{
int result;
result = _mali_internal_find_first_zero_bit( *addr );
/* non-negative signifies the bit was found */
if ( result >= 0 )
{
total += (u32)result;
break;
}
}
/* Now check if we reached maxbit or above */
if ( total >= maxbit )
{
total = maxbit;
}
return total; /* either the found bit nr, or maxbit if not found */
}
/** @} */ /* end group _mali_osk_bitops */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_OSK_BITOPS_H__ */

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_list.h
* Implementation of the OS abstraction layer for the kernel device driver
*/
#ifndef __MALI_OSK_LIST_H__
#define __MALI_OSK_LIST_H__
#ifdef __cplusplus
extern "C"
{
#endif
MALI_STATIC_INLINE void __mali_osk_list_add(_mali_osk_list_t *new_entry, _mali_osk_list_t *prev, _mali_osk_list_t *next)
{
next->prev = new_entry;
new_entry->next = next;
new_entry->prev = prev;
prev->next = new_entry;
}
MALI_STATIC_INLINE void __mali_osk_list_del(_mali_osk_list_t *prev, _mali_osk_list_t *next)
{
next->prev = prev;
prev->next = next;
}
/** @addtogroup _mali_osk_list
* @{ */
/** Reference implementations of Doubly-linked Circular Lists are provided.
* There is often no need to re-implement these.
*
* @note The implementation may differ subtly from any lists the OS provides.
* For this reason, these lists should not be mixed with OS-specific lists
* inside the OSK/UKK implementation. */
/** @brief Initialize a list element.
*
* All list elements must be initialized before use.
*
* Do not use on any list element that is present in a list without using
* _mali_osk_list_del first, otherwise this will break the list.
*
* @param list the list element to initialize
*/
MALI_STATIC_INLINE void _mali_osk_list_init( _mali_osk_list_t *list )
{
list->next = list;
list->prev = list;
}
/** @brief Insert a single list element after an entry in a list
*
* As an example, if this is inserted to the head of a list, then this becomes
* the first element of the list.
*
* Do not use to move list elements from one list to another, as it will break
* the originating list.
*
*
* @param newlist the list element to insert
* @param list the list in which to insert. The new element will be the next
* entry in this list
*/
MALI_STATIC_INLINE void _mali_osk_list_add( _mali_osk_list_t *new_entry, _mali_osk_list_t *list )
{
__mali_osk_list_add(new_entry, list, list->next);
}
/** @brief Insert a single list element before an entry in a list
*
* As an example, if this is inserted to the head of a list, then this becomes
* the last element of the list.
*
* Do not use to move list elements from one list to another, as it will break
* the originating list.
*
* @param newlist the list element to insert
* @param list the list in which to insert. The new element will be the previous
* entry in this list
*/
MALI_STATIC_INLINE void _mali_osk_list_addtail( _mali_osk_list_t *new_entry, _mali_osk_list_t *list )
{
__mali_osk_list_add(new_entry, list->prev, list);
}
/** @brief Remove a single element from a list
*
* The element will no longer be present in the list. The removed list element
* will be uninitialized, and so should not be traversed. It must be
* initialized before further use.
*
* @param list the list element to remove.
*/
MALI_STATIC_INLINE void _mali_osk_list_del( _mali_osk_list_t *list )
{
__mali_osk_list_del(list->prev, list->next);
}
/** @brief Remove a single element from a list, and re-initialize it
*
* The element will no longer be present in the list. The removed list element
* will initialized, and so can be used as normal.
*
* @param list the list element to remove and initialize.
*/
MALI_STATIC_INLINE void _mali_osk_list_delinit( _mali_osk_list_t *list )
{
__mali_osk_list_del(list->prev, list->next);
_mali_osk_list_init(list);
}
/** @brief Determine whether a list is empty.
*
* An empty list is one that contains a single element that points to itself.
*
* @param list the list to check.
* @return non-zero if the list is empty, and zero otherwise.
*/
MALI_STATIC_INLINE int _mali_osk_list_empty( _mali_osk_list_t *list )
{
return list->next == list;
}
/** @brief Move a list element from one list to another.
*
* The list element must be initialized.
*
* As an example, moving a list item to the head of a new list causes this item
* to be the first element in the new list.
*
* @param move the list element to move
* @param list the new list into which the element will be inserted, as the next
* element in the list.
*/
MALI_STATIC_INLINE void _mali_osk_list_move( _mali_osk_list_t *move_entry, _mali_osk_list_t *list )
{
__mali_osk_list_del(move_entry->prev, move_entry->next);
_mali_osk_list_add(move_entry, list);
}
/** @brief Join two lists
*
* The list element must be initialized.
*
* Allows you to join a list into another list at a specific location
*
* @param list the new list to add
* @param at the location in a list to add the new list into
*/
MALI_STATIC_INLINE void _mali_osk_list_splice( _mali_osk_list_t *list, _mali_osk_list_t *at )
{
if (!_mali_osk_list_empty(list))
{
/* insert all items from 'list' after 'at' */
_mali_osk_list_t *first = list->next;
_mali_osk_list_t *last = list->prev;
_mali_osk_list_t *split = at->next;
first->prev = at;
at->next = first;
last->next = split;
split->prev = last;
}
}
/** @} */ /* end group _mali_osk_list */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_OSK_LIST_H__ */

View File

@@ -0,0 +1,252 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_mali.h
* Defines the OS abstraction layer which is specific for the Mali kernel device driver (OSK)
*/
#ifndef __MALI_OSK_MALI_H__
#define __MALI_OSK_MALI_H__
#include <mali_osk.h>
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup _mali_osk_miscellaneous
* @{ */
/** @brief Initialize the OSK layer
*
* This function is used to setup any initialization of OSK functionality, if
* required.
*
* This must be the first function called from the common code, specifically,
* from the common code entry-point, mali_kernel_constructor.
*
* The OS-integration into the OS's kernel must handle calling of
* mali_kernel_constructor when the device driver is loaded.
*
* @return _MALI_OSK_ERR_OK on success, or a suitable _mali_osk_errcode_t on
* failure.
*/
_mali_osk_errcode_t _mali_osk_init( void );
/** @brief Terminate the OSK layer
*
* This function is used to terminate any resources initialized by
* _mali_osk_init.
*
* This must be the last function called from the common code, specifically,
* from the common code closedown function, mali_kernel_destructor, and the
* error path in mali_kernel_constructor.
*
* The OS-integration into the OS's kernel must handle calling of
* mali_kernel_destructor when the device driver is terminated.
*/
void _mali_osk_term( void );
/** @brief Read the Mali Resource configuration
*
* Populates a _mali_arch_resource_t array from configuration settings, which
* are stored in an OS-specific way.
*
* For example, these may be compiled in to a static structure, or read from
* the filesystem at startup.
*
* On failure, do not call _mali_osk_resources_term.
*
* @param arch_config a pointer to the store the pointer to the resources
* @param num_resources the number of resources read
* @return _MALI_OSK_ERR_OK on success. _MALI_OSK_ERR_NOMEM on allocation
* error. For other failures, a suitable _mali_osk_errcode_t is returned.
*/
_mali_osk_errcode_t _mali_osk_resources_init( _mali_osk_resource_t **arch_config, u32 *num_resources );
/** @brief Free resources allocated by _mali_osk_resources_init.
*
* Frees the _mali_arch_resource_t array allocated by _mali_osk_resources_init
*
* @param arch_config a pointer to the stored the pointer to the resources
* @param num_resources the number of resources in the array
*/
void _mali_osk_resources_term( _mali_osk_resource_t **arch_config, u32 num_resources);
/** @} */ /* end group _mali_osk_miscellaneous */
/** @addtogroup _mali_osk_low_level_memory
* @{ */
/** @brief Initialize a user-space accessible memory range
*
* This initializes a virtual address range such that it is reserved for the
* current process, but does not map any physical pages into this range.
*
* This function may initialize or adjust any members of the
* mali_memory_allocation \a descriptor supplied, before the physical pages are
* mapped in with _mali_osk_mem_mapregion_map().
*
* The function will always be called with MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE
* set in \a descriptor->flags. It is an error to call this function without
* setting this flag. Otherwise, \a descriptor->flags bits are reserved for
* future expansion
*
* The \a descriptor's process_addr_mapping_info member can be modified to
* allocate OS-specific information. Note that on input, this will be a
* ukk_private word from the U/K inteface, as inserted by _mali_ukk_mem_mmap().
* This is used to pass information from the U/K interface to the OSK interface,
* if necessary. The precise usage of the process_addr_mapping_info member
* depends on the U/K implementation of _mali_ukk_mem_mmap().
*
* Therefore, the U/K implementation of _mali_ukk_mem_mmap() and the OSK
* implementation of _mali_osk_mem_mapregion_init() must agree on the meaning and
* usage of the ukk_private word and process_addr_mapping_info member.
*
* Refer to \ref u_k_api for more information on the U/K interface.
*
* On successful return, \a descriptor's mapping member will be correct for
* use with _mali_osk_mem_mapregion_term() and _mali_osk_mem_mapregion_map().
*
* @param descriptor the mali_memory_allocation to initialize.
*/
_mali_osk_errcode_t _mali_osk_mem_mapregion_init( mali_memory_allocation * descriptor );
/** @brief Terminate a user-space accessible memory range
*
* This terminates a virtual address range reserved in the current user process,
* where none, some or all of the virtual address ranges have mappings to
* physical pages.
*
* It will unmap any physical pages that had been mapped into a reserved
* virtual address range for the current process, and then releases the virtual
* address range. Any extra book-keeping information or resources allocated
* during _mali_osk_mem_mapregion_init() will also be released.
*
* The \a descriptor itself is not freed - this must be handled by the caller of
* _mali_osk_mem_mapregion_term().
*
* The function will always be called with MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE
* set in descriptor->flags. It is an error to call this function without
* setting this flag. Otherwise, descriptor->flags bits are reserved for
* future expansion
*
* @param descriptor the mali_memory_allocation to terminate.
*/
void _mali_osk_mem_mapregion_term( mali_memory_allocation * descriptor );
/** @brief Map physical pages into a user process's virtual address range
*
* This is used to map a number of physically contigous pages into a
* user-process's virtual address range, which was previously reserved by a
* call to _mali_osk_mem_mapregion_init().
*
* This need not provide a mapping for the entire virtual address range
* reserved for \a descriptor - it may be used to map single pages per call.
*
* The function will always be called with MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE
* set in \a descriptor->flags. It is an error to call this function without
* setting this flag. Otherwise, \a descriptor->flags bits are reserved for
* future expansion
*
* The function may supply \a *phys_addr == \ref MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC.
* In this case, \a size must be set to \ref _MALI_OSK_CPU_PAGE_SIZE, and the function
* will allocate the physical page itself. The physical address of the
* allocated page will be returned through \a phys_addr.
*
* It is an error to set \a size != \ref _MALI_OSK_CPU_PAGE_SIZE while
* \a *phys_addr == \ref MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC,
* since it is not always possible for OSs to support such a setting through this
* interface.
*
* @note \b IMPORTANT: This code must validate the input parameters. If the
* range defined by \a offset and \a size is outside the range allocated in
* \a descriptor, then this function \b MUST not attempt any mapping, and must
* instead return a suitable \ref _mali_osk_errcode_t \b failure code.
*
* @param[in,out] descriptor the mali_memory_allocation representing the
* user-process's virtual address range to map into.
*
* @param[in] offset the offset into the virtual address range. This is only added
* to the mapping member of the \a descriptor, and not the \a phys_addr parameter.
* It must be a multiple of \ref _MALI_OSK_CPU_PAGE_SIZE.
*
* @param[in,out] phys_addr a pointer to the physical base address to begin the
* mapping from. If \a size == \ref _MALI_OSK_CPU_PAGE_SIZE and
* \a *phys_addr == \ref MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, then this
* function will allocate the physical page itself, and return the
* physical address of the page through \a phys_addr, which will be aligned to
* \ref _MALI_OSK_CPU_PAGE_SIZE. Otherwise, \a *phys_addr must be aligned to
* \ref _MALI_OSK_CPU_PAGE_SIZE, and is unmodified after the call.
* \a phys_addr is unaffected by the \a offset parameter.
*
* @param[in] size the number of bytes to map in. This must be a multiple of
* \ref _MALI_OSK_CPU_PAGE_SIZE.
*
* @return _MALI_OSK_ERR_OK on sucess, otherwise a _mali_osk_errcode_t value
* on failure
*
* @note could expand to use _mali_osk_mem_mapregion_flags_t instead of
* \ref MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, but note that we must
* also modify the mali process address manager in the mmu/memory engine code.
*/
_mali_osk_errcode_t _mali_osk_mem_mapregion_map( mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size );
/** @brief Unmap physical pages from a user process's virtual address range
*
* This is used to unmap a number of physically contigous pages from a
* user-process's virtual address range, which were previously mapped by a
* call to _mali_osk_mem_mapregion_map(). If the range specified was allocated
* from OS memory, then that memory will be returned to the OS. Whilst pages
* will be mapped out, the Virtual address range remains reserved, and at the
* same base address.
*
* When this function is used to unmap pages from OS memory
* (_mali_osk_mem_mapregion_map() was called with *phys_addr ==
* \ref MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC), then the \a flags must
* include \ref _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR. This is because
* it is not always easy for an OS implementation to discover whether the
* memory was OS allocated or not (and so, how it should release the memory).
*
* For this reason, only a range of pages of the same allocation type (all OS
* allocated, or none OS allocacted) may be unmapped in one call. Multiple
* calls must be made if allocations of these different types exist across the
* entire region described by the \a descriptor.
*
* The function will always be called with MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE
* set in \a descriptor->flags. It is an error to call this function without
* setting this flag. Otherwise, \a descriptor->flags bits are reserved for
* future expansion
*
* @param[in,out] descriptor the mali_memory_allocation representing the
* user-process's virtual address range to map into.
*
* @param[in] offset the offset into the virtual address range. This is only added
* to the mapping member of the \a descriptor. \a offset must be a multiple of
* \ref _MALI_OSK_CPU_PAGE_SIZE.
*
* @param[in] size the number of bytes to unmap. This must be a multiple of
* \ref _MALI_OSK_CPU_PAGE_SIZE.
*
* @param[in] flags specifies how the memory should be unmapped. For a range
* of pages that were originally OS allocated, this must have
* \ref _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR set.
*/
void _mali_osk_mem_mapregion_unmap( mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t flags );
/** @} */ /* end group _mali_osk_low_level_memory */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_OSK_MALI_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,710 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_ukk.h
* Defines the kernel-side interface of the user-kernel interface
*/
#ifndef __MALI_UKK_H__
#define __MALI_UKK_H__
#include "mali_osk.h"
#include "mali_uk_types.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup uddapi Unified Device Driver (UDD) APIs
*
* @{
*/
/**
* @addtogroup u_k_api UDD User/Kernel Interface (U/K) APIs
*
* - The _mali_uk functions are an abstraction of the interface to the device
* driver. On certain OSs, this would be implemented via the IOCTL interface.
* On other OSs, it could be via extension of some Device Driver Class, or
* direct function call for Bare metal/RTOSs.
* - It is important to note that:
* - The Device Driver has implemented the _mali_ukk set of functions
* - The Base Driver calls the corresponding set of _mali_uku functions.
* - What requires porting is solely the calling mechanism from User-side to
* Kernel-side, and propagating back the results.
* - Each U/K function is associated with a (group, number) pair from
* \ref _mali_uk_functions to make it possible for a common function in the
* Base Driver and Device Driver to route User/Kernel calls from/to the
* correct _mali_uk function. For example, in an IOCTL system, the IOCTL number
* would be formed based on the group and number assigned to the _mali_uk
* function, as listed in \ref _mali_uk_functions. On the user-side, each
* _mali_uku function would just make an IOCTL with the IOCTL-code being an
* encoded form of the (group, number) pair. On the kernel-side, the Device
* Driver's IOCTL handler decodes the IOCTL-code back into a (group, number)
* pair, and uses this to determine which corresponding _mali_ukk should be
* called.
* - Refer to \ref _mali_uk_functions for more information about this
* (group, number) pairing.
* - In a system where there is no distinction between user and kernel-side,
* the U/K interface may be implemented as:@code
* MALI_STATIC_INLINE _mali_osk_errcode_t _mali_uku_examplefunction( _mali_uk_examplefunction_s *args )
* {
* return mali_ukk_examplefunction( args );
* }
* @endcode
* - Therefore, all U/K calls behave \em as \em though they were direct
* function calls (but the \b implementation \em need \em not be a direct
* function calls)
*
* @note Naming the _mali_uk functions the same on both User and Kernel sides
* on non-RTOS systems causes debugging issues when setting breakpoints. In
* this case, it is not clear which function the breakpoint is put on.
* Therefore the _mali_uk functions in user space are prefixed with \c _mali_uku
* and in kernel space with \c _mali_ukk. The naming for the argument
* structures is unaffected.
*
* - The _mali_uk functions are synchronous.
* - Arguments to the _mali_uk functions are passed in a structure. The only
* parameter passed to the _mali_uk functions is a pointer to this structure.
* This first member of this structure, ctx, is a pointer to a context returned
* by _mali_uku_open(). For example:@code
* typedef struct
* {
* void *ctx;
* u32 number_of_cores;
* } _mali_uk_get_gp_number_of_cores_s;
* @endcode
*
* - Each _mali_uk function has its own argument structure named after the
* function. The argument is distinguished by the _s suffix.
* - The argument types are defined by the base driver and user-kernel
* interface.
* - All _mali_uk functions return a standard \ref _mali_osk_errcode_t.
* - Only arguments of type input or input/output need be initialized before
* calling a _mali_uk function.
* - Arguments of type output and input/output are only valid when the
* _mali_uk function returns \ref _MALI_OSK_ERR_OK.
* - The \c ctx member is always invalid after it has been used by a
* _mali_uk function, except for the context management functions
*
*
* \b Interface \b restrictions
*
* The requirements of the interface mean that an implementation of the
* User-kernel interface may do no 'real' work. For example, the following are
* illegal in the User-kernel implementation:
* - Calling functions necessary for operation on all systems, which would
* not otherwise get called on RTOS systems.
* - For example, a U/K interface that calls multiple _mali_ukk functions
* during one particular U/K call. This could not be achieved by the same code
* which uses direct function calls for the U/K interface.
* - Writing in values to the args members, when otherwise these members would
* not hold a useful value for a direct function call U/K interface.
* - For example, U/K interface implementation that take NULL members in
* their arguments structure from the user side, but those members are
* replaced with non-NULL values in the kernel-side of the U/K interface
* implementation. A scratch area for writing data is one such example. In this
* case, a direct function call U/K interface would segfault, because no code
* would be present to replace the NULL pointer with a meaningful pointer.
* - Note that we discourage the case where the U/K implementation changes
* a NULL argument member to non-NULL, and then the Device Driver code (outside
* of the U/K layer) re-checks this member for NULL, and corrects it when
* necessary. Whilst such code works even on direct function call U/K
* intefaces, it reduces the testing coverage of the Device Driver code. This
* is because we have no way of testing the NULL == value path on an OS
* implementation.
*
* A number of allowable examples exist where U/K interfaces do 'real' work:
* - The 'pointer switching' technique for \ref _mali_ukk_get_system_info
* - In this case, without the pointer switching on direct function call
* U/K interface, the Device Driver code still sees the same thing: a pointer
* to which it can write memory. This is because such a system has no
* distinction between a user and kernel pointer.
* - Writing an OS-specific value into the ukk_private member for
* _mali_ukk_mem_mmap().
* - In this case, this value is passed around by Device Driver code, but
* its actual value is never checked. Device Driver code simply passes it from
* the U/K layer to the OSK layer, where it can be acted upon. In this case,
* \em some OS implementations of the U/K (_mali_ukk_mem_mmap()) and OSK
* (_mali_osk_mem_mapregion_init()) functions will collaborate on the
* meaning of ukk_private member. On other OSs, it may be unused by both
* U/K and OSK layers
* - On OS systems (not including direct function call U/K interface
* implementations), _mali_ukk_get_big_block() may succeed, but the subsequent
* copying to user space may fail.
* - A problem scenario exists: some memory has been reserved by
* _mali_ukk_get_big_block(), but the user-mode will be unaware of it (it will
* never receive any information about this memory). In this case, the U/K
* implementation must do everything necessary to 'rollback' the \em atomic
* _mali_ukk_get_big_block() transaction.
* - Therefore, on error inside the U/K interface implementation itself,
* it will be as though the _mali_ukk function itself had failed, and cleaned
* up after itself.
* - Compare this to a direct function call U/K implementation, where all
* error cleanup is handled by the _mali_ukk function itself. The direct
* function call U/K interface implementation is automatically atomic.
*
* The last example highlights a consequence of all U/K interface
* implementations: they must be atomic with respect to the Device Driver code.
* And therefore, should Device Driver code succeed but the U/K implementation
* fail afterwards (but before return to user-space), then the U/K
* implementation must cause appropriate cleanup actions to preserve the
* atomicity of the interface.
*
* @{
*/
/** @defgroup _mali_uk_context U/K Context management
*
* These functions allow for initialisation of the user-kernel interface once per process.
*
* Generally the context will store the OS specific object to communicate with the kernel device driver and further
* state information required by the specific implementation. The context is shareable among all threads in the caller process.
*
* On IOCTL systems, this is likely to be a file descriptor as a result of opening the kernel device driver.
*
* On a bare-metal/RTOS system with no distinction between kernel and
* user-space, the U/K interface simply calls the _mali_ukk variant of the
* function by direct function call. In this case, the context returned is the
* mali_session_data from _mali_ukk_open().
*
* The kernel side implementations of the U/K interface expect the first member of the argument structure to
* be the context created by _mali_uku_open(). On some OS implementations, the meaning of this context
* will be different between user-side and kernel-side. In which case, the kernel-side will need to replace this context
* with the kernel-side equivalent, because user-side will not have access to kernel-side data. The context parameter
* in the argument structure therefore has to be of type input/output.
*
* It should be noted that the caller cannot reuse the \c ctx member of U/K
* argument structure after a U/K call, because it may be overwritten. Instead,
* the context handle must always be stored elsewhere, and copied into
* the appropriate U/K argument structure for each user-side call to
* the U/K interface. This is not usually a problem, since U/K argument
* structures are usually placed on the stack.
*
* @{ */
/** @brief Begin a new Mali Device Driver session
*
* This is used to obtain a per-process context handle for all future U/K calls.
*
* @param context pointer to storage to return a (void*)context handle.
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_open( void **context );
/** @brief End a Mali Device Driver session
*
* This should be called when the process no longer requires use of the Mali Device Driver.
*
* The context handle must not be used after it has been closed.
*
* @param context pointer to a stored (void*)context handle.
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_close( void **context );
/** @} */ /* end group _mali_uk_context */
/** @addtogroup _mali_uk_core U/K Core
*
* The core functions provide the following functionality:
* - verify that the user and kernel API are compatible
* - retrieve information about the cores and memory banks in the system
* - wait for the result of jobs started on a core
*
* @{ */
/** @brief Returns the size of the buffer needed for a _mali_ukk_get_system_info call
*
* This function must be called before a call is made to
* _mali_ukk_get_system_info, so that memory of the correct size can be
* allocated, and a pointer to this memory written into the system_info member
* of _mali_uk_get_system_info_s.
*
* @param args see _mali_uk_get_system_info_size_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_system_info_size( _mali_uk_get_system_info_size_s *args );
/** @brief Returns information about the system (cores and memory banks)
*
* A buffer for this needs to be allocated by the caller. The size of the buffer required is returned by
* _mali_ukk_get_system_info_size(). The user is responsible for freeing the buffer.
*
* The _mali_system_info structure will be written to the start of this buffer,
* and the core_info and mem_info lists will be written to locations inside
* the buffer, and will be suitably aligned.
*
* Under OS implementations of the U/K interface we need to pack/unpack
* pointers across the user/kernel boundary. This has required that we malloc()
* an intermediate buffer inside the kernel-side U/K interface, and free it
* before returning to user-side. To avoid modifying common code, we do the
* following pseudo-code, which we shall call 'pointer switching':
*
* @code
* {
* Copy_From_User(kargs, args, ... );
* void __user * local_ptr = kargs->system_info;
* kargs->system_info = _mali_osk_malloc( ... );
* _mali_ukk_get_system_info( kargs );
* Copy_To_User( local_ptr, kargs->system_info, ... );
* _mali_osk_free( kargs->system_info );
* }
* @endcode
* @note The user-side's args->system_info members was unmodified here.
*
* However, the current implementation requires an extra ukk_private word so that the common code can work out
* how to patch pointers to user-mode for an OS's U/K implementation, this should be set to the user-space
* destination address for pointer-patching to occur. When NULL, it is unused, an no pointer-patching occurs in the
* common code.
*
* @param args see _mali_uk_get_system_info_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args );
/** @brief Waits for a job notification.
*
* Sleeps until notified or a timeout occurs. Returns information about the notification.
*
* @param args see _mali_uk_wait_for_notification_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args );
/** @brief Post a notification to the notification queue of this application.
*
* @param args see _mali_uk_post_notification_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args );
/** @brief Verifies if the user and kernel side of this API are compatible.
*
* @param args see _mali_uk_get_api_version_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args );
/** @} */ /* end group _mali_uk_core */
/** @addtogroup _mali_uk_memory U/K Memory
*
* The memory functions provide functionality with and without a Mali-MMU present.
*
* For Mali-MMU based systems, the following functionality is provided:
* - Initialize and terminate MALI virtual address space
* - Allocate/deallocate physical memory to a MALI virtual address range and map into/unmap from the
* current process address space
* - Map/unmap external physical memory into the MALI virtual address range
*
* For Mali-nonMMU based systems:
* - Allocate/deallocate MALI memory
*
* @{ */
/**
* @brief Initialize the Mali-MMU Memory system
*
* For Mali-MMU builds of the drivers, this function must be called before any
* other functions in the \ref _mali_uk_memory group are called.
*
* @note This function is for Mali-MMU builds \b only. It should not be called
* when the drivers are built without Mali-MMU support.
*
* @param args see \ref _mali_uk_init_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable
* _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args );
/**
* @brief Terminate the MMU Memory system
*
* For Mali-MMU builds of the drivers, this function must be called when
* functions in the \ref _mali_uk_memory group will no longer be called. This
* function must be called before the application terminates.
*
* @note This function is for Mali-MMU builds \b only. It should not be called
* when the drivers are built without Mali-MMU support.
*
* @param args see \ref _mali_uk_term_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable
* _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args );
/** @brief Map a block of memory into the current user process
*
* Allocates a minimum of minimum_size_requested bytes of MALI memory and maps it into the current
* process space. The number of bytes allocated is returned in args->block_size.
*
* This is only used for Mali-nonMMU mode.
*
* @param args see _mali_uk_get_big_block_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args );
/** @brief Unmap a block of memory from the current user process
*
* Frees allocated MALI memory and unmaps it from the current process space. The previously allocated memory
* is indicated by the cookie as returned by _mali_ukk_get_big_block().
*
* This is only used for Mali-nonMMU mode.
*
* @param args see _mali_uk_free_big_block_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args );
/** @brief Map Mali Memory into the current user process
*
* Maps Mali memory into the current user process in a generic way.
*
* This function is to be used for Mali-MMU mode. The function is available in both Mali-MMU and Mali-nonMMU modes,
* but should not be called by a user process in Mali-nonMMU mode. In Mali-nonMMU mode, the function is callable
* from the kernel side, and is used to implement _mali_ukk_get_big_block() in this case.
*
* The implementation and operation of _mali_ukk_mem_mmap() is dependant on whether the driver is built for Mali-MMU
* or Mali-nonMMU:
* - In the nonMMU case, _mali_ukk_mem_mmap() requires a physical address to be specified. For this reason, an OS U/K
* implementation should not allow this to be called from user-space. In any case, nonMMU implementations are
* inherently insecure, and so the overall impact is minimal. Mali-MMU mode should be used if security is desired.
* - In the MMU case, _mali_ukk_mem_mmap() the _mali_uk_mem_mmap_s::phys_addr
* member is used for the \em Mali-virtual address desired for the mapping. The
* implementation of _mali_ukk_mem_mmap() will allocate both the CPU-virtual
* and CPU-physical addresses, and can cope with mapping a contiguous virtual
* address range to a sequence of non-contiguous physical pages. In this case,
* the CPU-physical addresses are not communicated back to the user-side, as
* they are unnecsessary; the \em Mali-virtual address range must be used for
* programming Mali structures.
*
* This means that in the first (nonMMU) case, the caller must manage the physical address allocations. The caller
* in this case is _mali_ukk_get_big_block(), which does indeed manage the Mali physical address ranges.
*
* In the second (MMU) case, _mali_ukk_mem_mmap() handles management of
* CPU-virtual and CPU-physical ranges, but the \em caller must manage the
* \em Mali-virtual address range from the user-side.
*
* @note Mali-virtual address ranges are entirely separate between processes.
* It is not possible for a process to accidentally corrupt another process'
* \em Mali-virtual address space.
*
* @param args see _mali_uk_mem_mmap_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args );
/** @brief Unmap Mali Memory from the current user process
*
* Unmaps Mali memory from the current user process in a generic way. This only operates on Mali memory supplied
* from _mali_ukk_mem_mmap().
*
* @param args see _mali_uk_mem_munmap_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args );
/** @brief Determine the buffer size necessary for an MMU page table dump.
* @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args );
/** @brief Dump MMU Page tables.
* @param args see _mali_uk_dump_mmu_page_table_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args );
/** @brief Map a physically contiguous range of memory into Mali
* @param args see _mali_uk_map_external_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args );
/** @brief Unmap a physically contiguous range of memory from Mali
* @param args see _mali_uk_unmap_external_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args );
#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0
/** @brief Map UMP memory into Mali
* @param args see _mali_uk_attach_ump_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args );
/** @brief Unmap UMP memory from Mali
* @param args see _mali_uk_release_ump_mem_s in mali_uk_types.h
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args );
#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER */
/** @brief Determine virtual-to-physical mapping of a contiguous memory range
* (optional)
*
* This allows the user-side to do a virtual-to-physical address translation.
* In conjunction with _mali_uku_map_external_mem, this can be used to do
* direct rendering.
*
* This function will only succeed on a virtual range that is mapped into the
* current process, and that is contigious.
*
* If va is not page-aligned, then it is rounded down to the next page
* boundary. The remainer is added to size, such that ((u32)va)+size before
* rounding is equal to ((u32)va)+size after rounding. The rounded modified
* va and size will be written out into args on success.
*
* If the supplied size is zero, or not a multiple of the system's PAGE_SIZE,
* then size will be rounded up to the next multiple of PAGE_SIZE before
* translation occurs. The rounded up size will be written out into args on
* success.
*
* On most OSs, virtual-to-physical address translation is a priveledged
* function. Therefore, the implementer must validate the range supplied, to
* ensure they are not providing arbitrary virtual-to-physical address
* translations. While it is unlikely such a mechanism could be used to
* compromise the security of a system on its own, it is possible it could be
* combined with another small security risk to cause a much larger security
* risk.
*
* @note This is an optional part of the interface, and is only used by certain
* implementations of libEGL. If the platform layer in your libEGL
* implementation does not require Virtual-to-Physical address translation,
* then this function need not be implemented. A stub implementation should not
* be required either, as it would only be removed by the compiler's dead code
* elimination.
*
* @note if implemented, this function is entirely platform-dependant, and does
* not exist in common code.
*
* @param args see _mali_uk_va_to_mali_pa_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args );
/** @} */ /* end group _mali_uk_memory */
/** @addtogroup _mali_uk_pp U/K Fragment Processor
*
* The Fragment Processor (aka PP (Pixel Processor)) functions provide the following functionality:
* - retrieving version of the fragment processors
* - determine number of fragment processors
* - starting a job on a fragment processor
*
* @{ */
/** @brief Issue a request to start a new job on a Fragment Processor.
*
* If the request fails args->status is set to _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE and you can
* try to start the job again.
*
* An existing job could be returned for requeueing if the new job has a higher priority than a previously started job
* which the hardware hasn't actually started processing yet. In this case the new job will be started instead and the
* existing one returned, otherwise the new job is started and the status field args->status is set to
* _MALI_UK_START_JOB_STARTED.
*
* If an existing lower priority job is returned, args->returned_user_job_ptr contains a
* pointer to the returned job and the status field args->status is set to
* _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED.
*
* Job completion can be awaited with _mali_ukk_wait_for_notification().
*
* @param args see _mali_uk_pp_start_job_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_pp_start_job( _mali_uk_pp_start_job_s *args );
/** @brief Returns the number of Fragment Processors in the system
*
* @param args see _mali_uk_get_pp_number_of_cores_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args );
/** @brief Returns the version that all Fragment Processor cores are compatible with.
*
* This function may only be called when _mali_ukk_get_pp_number_of_cores() indicated at least one Fragment
* Processor core is available.
*
* @param args see _mali_uk_get_pp_core_version_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args );
/** @brief Abort any PP jobs with the given ID.
*
* Jobs internally queued or currently running on the hardware is to be stopped/aborted.
* Jobs aborted are reported via the normal job completion system.
* Any jobs, running or internally queued should be aborted imediately.
* Normal notifiction procedures to report on the status of these jobs.
*
*
* @param args see _malu_uk_pp_abort_job_s in "mali_uk_types.h"
*/
void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s *args );
/** @} */ /* end group _mali_uk_pp */
/** @addtogroup _mali_uk_gp U/K Vertex Processor
*
* The Vertex Processor (aka GP (Geometry Processor)) functions provide the following functionality:
* - retrieving version of the Vertex Processors
* - determine number of Vertex Processors available
* - starting a job on a Vertex Processor
*
* @{ */
/** @brief Issue a request to start a new job on a Vertex Processor.
*
* If the request fails args->status is set to _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE and you can
* try to start the job again.
*
* An existing job could be returned for requeueing if the new job has a higher priority than a previously started job
* which the hardware hasn't actually started processing yet. In this case the new job will be started and the
* existing one returned, otherwise the new job is started and the status field args->status is set to
* _MALI_UK_START_JOB_STARTED.
*
* If an existing lower priority job is returned, args->returned_user_job_ptr contains a pointer to
* the returned job and the status field args->status is set to
* _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED.
*
* Job completion can be awaited with _mali_ukk_wait_for_notification().
*
* @param args see _mali_uk_gp_start_job_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_gp_start_job( _mali_uk_gp_start_job_s *args );
/** @brief Returns the number of Vertex Processors in the system.
*
* @param args see _mali_uk_get_gp_number_of_cores_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args );
/** @brief Returns the version that all Vertex Processor cores are compatible with.
*
* This function may only be called when _mali_uk_get_gp_number_of_cores() indicated at least one Vertex
* Processor core is available.
*
* @param args see _mali_uk_get_gp_core_version_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args );
/** @brief Resume or abort suspended Vertex Processor jobs.
*
* After receiving notification that a Vertex Processor job was suspended from
* _mali_ukk_wait_for_notification() you can use this function to resume or abort the job.
*
* @param args see _mali_uk_gp_suspend_response_s in "mali_uk_types.h"
* @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
*/
_mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args );
/** @brief Abort any GP jobs with the given ID.
*
* Jobs internally queued or currently running on the hardware is to be stopped/aborted.
* Jobs aborted are reported via the normal job completion system.
*
* Any jobs, running or internally queued should be aborted imediately.
* Normal notifiction procedures to report on the status of these jobs.
*
* @param args see _mali_uk_gp_abort_job_s in "mali_uk_types.h"
*/
void _mali_ukk_gp_abort_job( _mali_uk_gp_abort_job_s *args );
/** @} */ /* end group _mali_uk_gp */
#if USING_MALI_PMM
/** @addtogroup _mali_uk_pmm U/K Power Management Module
* @{ */
/* @brief Power Management Module event message
*
* @note The event message can fail to be sent due to OOM but this is
* stored in the PMM state machine to be handled later
*
* @param args see _mali_uk_pmm_event_message_s in "mali_uk_types.h"
*/
void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args );
/** @} */ /* end group _mali_uk_pmm */
#endif /* USING_MALI_PMM */
#if MALI_TIMELINE_PROFILING_ENABLED
/** @addtogroup _mali_uk_profiling U/K Timeline profiling module
* @{ */
/** @brief Start recording profiling events.
*
* @param args see _mali_uk_profiling_start_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args);
/** @brief Add event to profiling buffer.
*
* @param args see _mali_uk_profiling_add_event_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args);
/** @brief Stop recording profiling events.
*
* @param args see _mali_uk_profiling_stop_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args);
/** @brief Retrieve a recorded profiling event.
*
* @param args see _mali_uk_profiling_get_event_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args);
/** @brief Clear recorded profiling events.
*
* @param args see _mali_uk_profiling_clear_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args);
/** @} */ /* end group _mali_uk_profiling */
#endif
/** @addtogroup _mali_uk_vsync U/K VSYNC reporting module
* @{ */
/** @brief Report events related to vsync.
*
* @note Events should be reported when starting to wait for vsync and when the
* waiting is finished. This information can then be used in kernel space to
* complement the GPU utilization metric.
*
* @param args see _mali_uk_vsync_event_report_s in "mali_uk_types.h"
*/
_mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args);
/** @} */ /* end group _mali_uk_vsync */
/** @} */ /* end group u_k_api */
/** @} */ /* end group uddapi */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_UKK_H__ */

View File

@@ -0,0 +1,963 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm.c
* Implementation of the power management module for the kernel device driver
*/
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_subsystem.h"
#include "mali_pmm.h"
#include "mali_pmm_system.h"
#include "mali_pmm_state.h"
#include "mali_pmm_policy.h"
#include "mali_platform.h"
/* Internal PMM subsystem state */
static _mali_pmm_internal_state_t *pmm_state = NULL;
/* Mali kernel subsystem id */
static mali_kernel_subsystem_identifier mali_subsystem_pmm_id = -1;
static u32 pmm_cores_registered_mask = 0;
#define GET_PMM_STATE_PTR (pmm_state)
/* Internal functions */
static _mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource);
static void pmm_event_process( void );
_mali_osk_errcode_t malipmm_irq_uhandler(void *data);
void malipmm_irq_bhandler(void *data);
/** @brief Start the PMM subsystem
*
* @param id Subsystem id to uniquely identify this subsystem
* @return _MALI_OSK_ERR_OK if the system started successfully, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id );
/** @brief Perform post start up of the PMM subsystem
*
* Post start up includes initializing the current policy, now that the system is
* completely started - to stop policies turning off hardware during the start up
*
* @param id the unique subsystem id
* @return _MALI_OSK_ERR_OK if the post startup was successful, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id );
/** @brief Terminate the PMM subsystem
*
* @param id the unique subsystem id
*/
void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id );
#if MALI_STATE_TRACKING
u32 malipmm_subsystem_dump_state( char *buf, u32 size );
#endif
/* This will be one of the subsystems in the array of subsystems:
static struct mali_kernel_subsystem * subsystems[];
found in file: mali_kernel_core.c
*/
struct mali_kernel_subsystem mali_subsystem_pmm=
{
malipmm_kernel_subsystem_start, /* startup */
malipmm_kernel_subsystem_terminate, /* shutdown */
malipmm_kernel_load_complete, /* loaded all subsystems */
NULL,
NULL,
NULL,
NULL,
#if MALI_STATE_TRACKING
malipmm_subsystem_dump_state, /* dump_state */
#endif
};
#if PMM_OS_TEST
u32 power_test_event = 0;
mali_bool power_test_flag = MALI_FALSE;
_mali_osk_timer_t *power_test_timer = NULL;
void _mali_osk_pmm_power_up_done(mali_pmm_message_data data)
{
MALI_PRINT(("POWER TEST OS UP DONE\n"));
}
void _mali_osk_pmm_power_down_done(mali_pmm_message_data data)
{
MALI_PRINT(("POWER TEST OS DOWN DONE\n"));
}
/**
* Symbian OS Power Up call to the driver
*/
void power_test_callback( void *arg )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
power_test_flag = MALI_TRUE;
_mali_osk_irq_schedulework( pmm->irq );
}
void power_test_start()
{
power_test_timer = _mali_osk_timer_init();
_mali_osk_timer_setcallback( power_test_timer, power_test_callback, NULL );
/* First event is power down */
power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN;
_mali_osk_timer_add( power_test_timer, 10000 );
}
mali_bool power_test_check()
{
if( power_test_flag )
{
_mali_uk_pmm_message_s event = {
NULL,
0,
1 };
event.id = power_test_event;
power_test_flag = MALI_FALSE;
/* Send event */
_mali_ukk_pmm_event_message( &event );
/* Switch to next event to test */
if( power_test_event == MALI_PMM_EVENT_OS_POWER_DOWN )
{
power_test_event = MALI_PMM_EVENT_OS_POWER_UP;
}
else
{
power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN;
}
_mali_osk_timer_add( power_test_timer, 5000 );
return MALI_TRUE;
}
return MALI_FALSE;
}
void power_test_end()
{
_mali_osk_timer_del( power_test_timer );
_mali_osk_timer_term( power_test_timer );
power_test_timer = NULL;
}
#endif
void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
_mali_osk_notification_t *msg;
mali_pmm_message_t *event;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(args);
MALIPMM_DEBUG_PRINT( ("PMM: sending message\n") );
#if MALI_PMM_TRACE && MALI_PMM_TRACE_SENT_EVENTS
_mali_pmm_trace_event_message( args, MALI_FALSE );
#endif
msg = _mali_osk_notification_create( MALI_PMM_NOTIFICATION_TYPE, sizeof( mali_pmm_message_t ) );
if( msg )
{
event = (mali_pmm_message_t *)msg->result_buffer;
event->id = args->id;
event->ts = _mali_osk_time_tickcount();
event->data = args->data;
_mali_osk_atomic_inc( &(pmm->messages_queued) );
if( args->id > MALI_PMM_EVENT_INTERNALS )
{
/* Internal PMM message */
_mali_osk_notification_queue_send( pmm->iqueue, msg );
#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
pmm->imessages_sent++;
#endif
}
else
{
/* Real event */
_mali_osk_notification_queue_send( pmm->queue, msg );
#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
pmm->messages_sent++;
#endif
}
}
else
{
MALI_PRINT_ERROR( ("PMM: Could not send message %d", args->id) );
/* Make note of this OOM - which has caused a missed event */
pmm->missed++;
}
/* Schedule time to look at the event or the fact we couldn't create an event */
_mali_osk_irq_schedulework( pmm->irq );
}
mali_pmm_state _mali_pmm_state( void )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
if( pmm && (mali_subsystem_pmm_id != -1) )
{
return pmm->state;
}
/* No working subsystem yet */
return MALI_PMM_STATE_UNAVAILABLE;
}
mali_pmm_core_mask _mali_pmm_cores_list( void )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
return pmm->cores_registered;
}
mali_pmm_core_mask _mali_pmm_cores_powered( void )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
return pmm->cores_powered;
}
_mali_osk_errcode_t _mali_pmm_list_policies(
u32 policy_list_size,
mali_pmm_policy *policy_list,
u32 *policies_available )
{
/* TBD - This is currently a stub function for basic power management */
MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED );
}
_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy )
{
/* TBD - This is currently a stub function for basic power management */
/* TBD - When this is not a stub... include tracing...
#if MALI_PMM_TRACE
_mali_pmm_trace_policy_change( old, newpolicy );
#endif
*/
MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED );
}
_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy )
{
if( policy )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
if( pmm )
{
*policy = pmm->policy;
MALI_SUCCESS;
}
else
{
*policy = MALI_PMM_POLICY_NONE;
MALI_ERROR( _MALI_OSK_ERR_FAULT );
}
}
/* No return argument */
MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS );
}
#if ( MALI_PMM_TRACE || MALI_STATE_TRACKING )
/* Event names - order must match mali_pmm_event_id enum */
static char *pmm_trace_events[] = {
"OS_POWER_UP",
"OS_POWER_DOWN",
"JOB_SCHEDULED",
"JOB_QUEUED",
"JOB_FINISHED",
"TIMEOUT",
};
/* State names - order must match mali_pmm_state enum */
static char *pmm_trace_state[] = {
"UNAVAILABLE",
"SYSTEM ON",
"SYSTEM OFF",
"SYSTEM TRANSITION",
};
/* Policy names - order must match mali_pmm_policy enum */
static char *pmm_trace_policy[] = {
"NONE",
"ALWAYS ON",
"JOB CONTROL",
};
/* Status names - order must match mali_pmm_status enum */
static char *pmm_trace_status[] = {
"MALI_PMM_STATUS_IDLE", /**< PMM is waiting next event */
"MALI_PMM_STATUS_POLICY_POWER_DOWN", /**< Policy initiated power down */
"MALI_PMM_STATUS_POLICY_POWER_UP", /**< Policy initiated power down */
"MALI_PMM_STATUS_OS_WAITING", /**< PMM is waiting for OS power up */
"MALI_PMM_STATUS_OS_POWER_DOWN", /**< OS initiated power down */
"MALI_PMM_STATUS_RUNTIME_IDLE_IN_PROGRESS",
"MALI_PMM_STATUS_DVFS_PAUSE", /**< PMM DVFS Status Pause */
"MALI_PMM_STATUS_OS_POWER_UP", /**< OS initiated power up */
"MALI_PMM_STATUS_OFF", /**< PMM is not active */
};
#endif /* MALI_PMM_TRACE || MALI_STATE_TRACKING */
#if MALI_PMM_TRACE
/* UK event names - order must match mali_pmm_event_id enum */
static char *pmm_trace_events_uk[] = {
"UKS",
"UK_EXAMPLE",
};
/* Internal event names - order must match mali_pmm_event_id enum */
static char *pmm_trace_events_internal[] = {
"INTERNALS",
"INTERNAL_POWER_UP_ACK",
"INTERNAL_POWER_DOWN_ACK",
};
void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate )
{
const char *dname;
const char *cname;
const char *ename;
if( old != newstate )
{
if( newstate == 0 )
{
dname = "NO cores";
}
else
{
dname = pmm_trace_get_core_name( newstate );
}
/* These state checks only work if the assumption that only cores can be
* turned on or turned off in seperate actions is true. If core power states can
* be toggled (some one, some off) at the same time, this check does not work
*/
if( old > newstate )
{
/* Cores have turned off */
cname = pmm_trace_get_core_name( old - newstate );
ename = "OFF";
}
else
{
/* Cores have turned on */
cname = pmm_trace_get_core_name( newstate - old );
ename = "ON";
}
MALI_PRINT( ("PMM Trace: Hardware %s ON, %s just turned %s. { 0x%08x -> 0x%08x }", dname, cname, ename, old, newstate) );
}
}
void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate )
{
if( old != newstate )
{
MALI_PRINT( ("PMM Trace: State changed from %s to %s", pmm_trace_state[old], pmm_trace_state[newstate]) );
}
}
void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy )
{
if( old != newpolicy )
{
MALI_PRINT( ("PMM Trace: Policy changed from %s to %s", pmm_trace_policy[old], pmm_trace_policy[newpolicy]) );
}
}
void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received )
{
const char *ename;
const char *dname;
const char *tname;
const char *format = "PMM Trace: Event %s { (%d) %s, %d ticks, (0x%x) %s }";
MALI_DEBUG_ASSERT_POINTER(event);
tname = (received) ? "received" : "sent";
if( event->id >= MALI_PMM_EVENT_INTERNALS )
{
ename = pmm_trace_events_internal[((int)event->id) - MALI_PMM_EVENT_INTERNALS];
}
else if( event->id >= MALI_PMM_EVENT_UKS )
{
ename = pmm_trace_events_uk[((int)event->id) - MALI_PMM_EVENT_UKS];
}
else
{
ename = pmm_trace_events[event->id];
}
switch( event->id )
{
case MALI_PMM_EVENT_OS_POWER_UP:
case MALI_PMM_EVENT_OS_POWER_DOWN:
dname = "os event";
break;
case MALI_PMM_EVENT_JOB_SCHEDULED:
case MALI_PMM_EVENT_JOB_QUEUED:
case MALI_PMM_EVENT_JOB_FINISHED:
case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
dname = pmm_trace_get_core_name( (mali_pmm_core_mask)event->data );
break;
case MALI_PMM_EVENT_TIMEOUT:
dname = "timeout start";
/* Print data with a different format */
format = "PMM Trace: Event %s { (%d) %s, %d ticks, %d ticks %s }";
break;
default:
dname = "unknown data";
}
MALI_PRINT( (format, tname, (u32)event->id, ename, event->ts, (u32)event->data, dname) );
}
#endif /* MALI_PMM_TRACE */
/****************** Mali Kernel API *****************/
_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id )
{
mali_subsystem_pmm_id = id;
MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(PMU, malipmm_create));
MALI_SUCCESS;
}
_mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource)
{
/* Create PMM state memory */
MALI_DEBUG_ASSERT( pmm_state == NULL );
pmm_state = (_mali_pmm_internal_state_t *) _mali_osk_malloc(sizeof(*pmm_state));
MALI_CHECK_NON_NULL( pmm_state, _MALI_OSK_ERR_NOMEM );
/* All values get 0 as default */
_mali_osk_memset(pmm_state, 0, sizeof(*pmm_state));
/* Set up the initial PMM state */
pmm_state->waiting = 0;
pmm_state->status = MALI_PMM_STATUS_IDLE;
pmm_state->state = MALI_PMM_STATE_UNAVAILABLE; /* Until a core registers */
/* Set up policy via compile time option for the moment */
#if MALI_PMM_ALWAYS_ON
pmm_state->policy = MALI_PMM_POLICY_ALWAYS_ON;
#else
pmm_state->policy = MALI_PMM_POLICY_JOB_CONTROL;
#endif
#if MALI_PMM_TRACE
_mali_pmm_trace_policy_change( MALI_PMM_POLICY_NONE, pmm_state->policy );
#endif
/* Set up assumes all values are initialized to NULL or MALI_FALSE, so
* we can exit halfway through set up and perform clean up
*/
#if !MALI_PMM_NO_PMU
if( mali_platform_init(resource) != _MALI_OSK_ERR_OK ) goto pmm_fail_cleanup;
pmm_state->pmu_initialized = MALI_TRUE;
#endif
pmm_state->queue = _mali_osk_notification_queue_init();
if( !pmm_state->queue ) goto pmm_fail_cleanup;
pmm_state->iqueue = _mali_osk_notification_queue_init();
if( !pmm_state->iqueue ) goto pmm_fail_cleanup;
/* We are creating an IRQ handler just for the worker thread it gives us */
pmm_state->irq = _mali_osk_irq_init( _MALI_OSK_IRQ_NUMBER_PMM,
malipmm_irq_uhandler,
malipmm_irq_bhandler,
NULL,
NULL,
(void *)pmm_state, /* PMM state is passed to IRQ */
"PMM handler" );
if( !pmm_state->irq ) goto pmm_fail_cleanup;
pmm_state->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 75);
if( !pmm_state->lock ) goto pmm_fail_cleanup;
if( _mali_osk_atomic_init( &(pmm_state->messages_queued), 0 ) != _MALI_OSK_ERR_OK )
{
goto pmm_fail_cleanup;
}
MALIPMM_DEBUG_PRINT( ("PMM: subsystem created, policy=%d\n", pmm_state->policy) );
MALI_SUCCESS;
pmm_fail_cleanup:
MALI_PRINT_ERROR( ("PMM: subsystem failed to be created\n") );
if( pmm_state )
{
_mali_osk_resource_type_t t = PMU;
if( pmm_state->lock ) _mali_osk_lock_term( pmm_state->lock );
if( pmm_state->irq ) _mali_osk_irq_term( pmm_state->irq );
if( pmm_state->queue ) _mali_osk_notification_queue_term( pmm_state->queue );
if( pmm_state->iqueue ) _mali_osk_notification_queue_term( pmm_state->iqueue );
if( pmm_state->pmu_initialized ) ( mali_platform_deinit(&t) );
_mali_osk_free(pmm_state);
pmm_state = NULL;
}
MALI_ERROR( _MALI_OSK_ERR_FAULT );
}
_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALIPMM_DEBUG_PRINT( ("PMM: subsystem loaded, policy initializing\n") );
#if PMM_OS_TEST
power_test_start();
#endif
/* Initialize the profile now the system has loaded - so that cores are
* not turned off during start up
*/
return pmm_policy_init( pmm );
}
void malipmm_force_powerup( void )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_LOCK(pmm);
pmm->status = MALI_PMM_STATUS_OFF;
pmm_cores_registered_mask = pmm->cores_registered;
if( ( pmm->status == MALI_PMM_STATUS_OS_POWER_DOWN ) && ( pmm->is_dvfs_active == 1 ) )
{
_mali_osk_pmm_dvfs_operation_done(0);
}
MALI_PMM_UNLOCK(pmm);
/* flush PMM workqueue */
_mali_osk_flush_workqueue( pmm->irq );
if (pmm->cores_powered == 0)
{
mali_platform_powerup(pmm_cores_registered_mask);
}
}
void malipmm_force_powerdown( void )
{
mali_platform_powerdown(pmm_cores_registered_mask);
}
void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id )
{
/* Check this is the right system */
MALI_DEBUG_ASSERT( id == mali_subsystem_pmm_id );
MALI_DEBUG_ASSERT_POINTER(pmm_state);
if( pmm_state )
{
_mali_osk_resource_type_t t = PMU;
#if PMM_OS_TEST
power_test_end();
#endif
/* Get the lock so we can shutdown */
MALI_PMM_LOCK(pmm_state);
#if MALI_STATE_TRACKING
pmm_state->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
pmm_state->status = MALI_PMM_STATUS_OFF;
#if MALI_STATE_TRACKING
pmm_state->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm_state);
pmm_policy_term(pmm_state);
_mali_osk_irq_term( pmm_state->irq );
_mali_osk_notification_queue_term( pmm_state->queue );
_mali_osk_notification_queue_term( pmm_state->iqueue );
if( pmm_state->pmu_initialized ) mali_platform_deinit(&t);
_mali_osk_atomic_term( &(pmm_state->messages_queued) );
MALI_PMM_LOCK_TERM(pmm_state);
_mali_osk_free(pmm_state);
pmm_state = NULL;
}
MALIPMM_DEBUG_PRINT( ("PMM: subsystem terminated\n") );
}
_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core )
{
_mali_osk_errcode_t err;
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
if( pmm == NULL )
{
/* PMM state has not been created, this is because the PMU resource has not been
* created yet.
* This probably means that the PMU resource has not been specfied as the first
* resource in the config file
*/
MALI_PRINT_ERROR( ("PMM: Cannot register core %s because the PMU resource has not been\n initialized. Please make sure the PMU resource is the first resource in the\n resource configuration.\n",
pmm_trace_get_core_name(core)) );
MALI_ERROR(_MALI_OSK_ERR_FAULT);
}
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* Check if the core is registered more than once in PMM */
MALI_DEBUG_ASSERT( (pmm->cores_registered & core) == 0 );
MALIPMM_DEBUG_PRINT( ("PMM: core registered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) );
#if !MALI_PMM_NO_PMU
/* Make sure the core is powered up */
err = mali_platform_powerup( core );
#else
err = _MALI_OSK_ERR_OK;
#endif
if( _MALI_OSK_ERR_OK == err )
{
#if MALI_PMM_TRACE
mali_pmm_core_mask old_power = pmm->cores_powered;
#endif
/* Assume a registered core is now powered up and idle */
pmm->cores_registered |= core;
pmm->cores_idle |= core;
pmm->cores_powered |= core;
pmm_update_system_state( pmm );
#if MALI_PMM_TRACE
_mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
#endif
}
else
{
MALI_PRINT_ERROR( ("PMM: Error(%d) powering up registered core: (0x%x) %s\n",
err, core, pmm_trace_get_core_name(core)) );
}
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
return err;
}
void malipmm_core_unregister( mali_pmm_core_id core )
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* Check if the core is registered in PMM */
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, core );
MALIPMM_DEBUG_PRINT( ("PMM: core unregistered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) );
{
#if MALI_PMM_TRACE
mali_pmm_core_mask old_power = pmm->cores_powered;
#endif
/* Remove the core from the system */
pmm->cores_registered &= (~core);
pmm->cores_idle &= (~core);
pmm->cores_powered &= (~core);
pmm->cores_pend_down &= (~core);
pmm->cores_pend_up &= (~core);
pmm->cores_ack_down &= (~core);
pmm->cores_ack_up &= (~core);
pmm_update_system_state( pmm );
#if MALI_PMM_TRACE
_mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
#endif
}
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
}
void malipmm_core_power_down_okay( mali_pmm_core_id core )
{
_mali_uk_pmm_message_s event = {
NULL,
MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK,
0 };
event.data = core;
_mali_ukk_pmm_event_message( &event );
}
void malipmm_set_policy_check()
{
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
MALI_DEBUG_ASSERT_POINTER(pmm);
pmm->check_policy = MALI_TRUE;
/* To check the policy we need to schedule some work */
_mali_osk_irq_schedulework( pmm->irq );
}
_mali_osk_errcode_t malipmm_irq_uhandler(void *data)
{
MALIPMM_DEBUG_PRINT( ("PMM: uhandler - not expected to be used\n") );
MALI_SUCCESS;
}
void malipmm_irq_bhandler(void *data)
{
_mali_pmm_internal_state_t *pmm;
pmm = (_mali_pmm_internal_state_t *)data;
MALI_DEBUG_ASSERT_POINTER(pmm);
#if PMM_OS_TEST
if( power_test_check() ) return;
#endif
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* Quick out when we are shutting down */
if( pmm->status == MALI_PMM_STATUS_OFF )
{
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
return;
}
MALIPMM_DEBUG_PRINT( ("PMM: bhandler - Processing event\n") );
if( pmm->missed > 0 )
{
MALI_PRINT_ERROR( ("PMM: Failed to send %d events", pmm->missed) );
pmm_fatal_reset( pmm );
}
if( pmm->check_policy )
{
pmm->check_policy = MALI_FALSE;
pmm_policy_check_policy(pmm);
}
else
{
/* Perform event processing */
pmm_event_process();
if( pmm->fatal_power_err )
{
/* Try a reset */
pmm_fatal_reset( pmm );
}
}
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
}
static void pmm_event_process( void )
{
_mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
_mali_osk_notification_t *msg = NULL;
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
mali_pmm_message_t *event;
u32 process_messages;
MALI_DEBUG_ASSERT_POINTER(pmm);
/* Max number of messages to process before exiting - as we shouldn't stay
* processing the messages for a long time
*/
process_messages = _mali_osk_atomic_read( &(pmm->messages_queued) );
while( process_messages > 0 )
{
/* Check internal message queue first */
err = _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg );
if( err != _MALI_OSK_ERR_OK )
{
if( pmm->status == MALI_PMM_STATUS_IDLE || pmm->status == MALI_PMM_STATUS_OS_WAITING || pmm->status == MALI_PMM_STATUS_DVFS_PAUSE)
{
if( pmm->waiting > 0 ) pmm->waiting--;
/* We aren't busy changing state, so look at real events */
err = _mali_osk_notification_queue_dequeue( pmm->queue, &msg );
if( err != _MALI_OSK_ERR_OK )
{
pmm->no_events++;
MALIPMM_DEBUG_PRINT( ("PMM: event_process - No message to process\n") );
/* Nothing to do - so return */
return;
}
else
{
#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
pmm->messages_received++;
#endif
}
}
else
{
/* Waiting for an internal message */
pmm->waiting++;
MALIPMM_DEBUG_PRINT( ("PMM: event_process - Waiting for internal message, messages queued=%d\n", pmm->waiting) );
return;
}
}
else
{
#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
pmm->imessages_received++;
#endif
}
MALI_DEBUG_ASSERT_POINTER( msg );
/* Check the message type matches */
MALI_DEBUG_ASSERT( msg->notification_type == MALI_PMM_NOTIFICATION_TYPE );
event = msg->result_buffer;
_mali_osk_atomic_dec( &(pmm->messages_queued) );
process_messages--;
#if MALI_PMM_TRACE
/* Trace before we process the event in case we have an error */
_mali_pmm_trace_event_message( event, MALI_TRUE );
#endif
err = pmm_policy_process( pmm, event );
if( err != _MALI_OSK_ERR_OK )
{
MALI_PRINT_ERROR( ("PMM: Error(%d) in policy %d when processing event message with id: %d",
err, pmm->policy, event->id) );
}
/* Delete notification */
_mali_osk_notification_delete ( msg );
if( pmm->fatal_power_err )
{
/* Nothing good has happened - exit */
return;
}
#if MALI_PMM_TRACE
MALI_PRINT( ("PMM Trace: Event processed, msgs (sent/read) = %d/%d, int msgs (sent/read) = %d/%d, no events = %d, waiting = %d\n",
pmm->messages_sent, pmm->messages_received, pmm->imessages_sent, pmm->imessages_received, pmm->no_events, pmm->waiting) );
#endif
}
if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->waiting > 0 )
{
/* For events we ignored whilst we were busy, add a new
* scheduled time to look at them */
_mali_osk_irq_schedulework( pmm->irq );
}
}
#if MALI_STATE_TRACKING
u32 malipmm_subsystem_dump_state(char *buf, u32 size)
{
int len = 0;
_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
if( !pmm )
{
len += _mali_osk_snprintf(buf + len, size + len, "PMM: Null state\n");
}
else
{
len += _mali_osk_snprintf(buf+len, size+len, "Locks:\n PMM lock acquired: %s\n",
pmm->mali_pmm_lock_acquired ? "true" : "false");
len += _mali_osk_snprintf(buf+len, size+len,
"PMM state:\n Previous status: %s\n Status: %s\n Current event: %s\n Policy: %s\n Check policy: %s\n State: %s\n",
pmm_trace_status[pmm->mali_last_pmm_status], pmm_trace_status[pmm->status],
pmm_trace_events[pmm->mali_new_event_status], pmm_trace_policy[pmm->policy],
pmm->check_policy ? "true" : "false", pmm_trace_state[pmm->state]);
len += _mali_osk_snprintf(buf+len, size+len,
"PMM cores:\n Cores registered: %d\n Cores powered: %d\n Cores idle: %d\n"
" Cores pending down: %d\n Cores pending up: %d\n Cores ack down: %d\n Cores ack up: %d\n",
pmm->cores_registered, pmm->cores_powered, pmm->cores_idle, pmm->cores_pend_down,
pmm->cores_pend_up, pmm->cores_ack_down, pmm->cores_ack_up);
len += _mali_osk_snprintf(buf+len, size+len, "PMM misc:\n PMU init: %s\n Messages queued: %d\n"
" Waiting: %d\n No events: %d\n Missed events: %d\n Fatal power error: %s\n",
pmm->pmu_initialized ? "true" : "false", _mali_osk_atomic_read(&(pmm->messages_queued)),
pmm->waiting, pmm->no_events, pmm->missed, pmm->fatal_power_err ? "true" : "false");
}
return len;
}
#endif /* MALI_STATE_TRACKING */
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,329 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm.h
* Defines the power management module for the kernel device driver
*/
#ifndef __MALI_PMM_H__
#define __MALI_PMM_H__
/* For mali_pmm_message_data and MALI_PMM_EVENT_UK_* defines */
#include "mali_uk_types.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @defgroup pmmapi Power Management Module APIs
*
* @{
*/
/** OS event tester */
#define PMM_OS_TEST 0
/** @brief Compile option to turn on/off tracing */
#define MALI_PMM_TRACE 0
#define MALI_PMM_TRACE_SENT_EVENTS 0
/** @brief Compile option to switch between always on or job control PMM policy */
#define MALI_PMM_ALWAYS_ON 0
/** @brief Overrides hardware PMU and uses software simulation instead
* @note This even stops intialization of PMU and cores being powered on at start up
*/
#define MALI_PMM_NO_PMU 0
/** @brief PMM debug print to control debug message level */
#define MALIPMM_DEBUG_PRINT(args) \
MALI_DEBUG_PRINT(3, args)
/** @brief power management event message identifiers.
*/
/* These must match up with the pmm_trace_events & pmm_trace_events_internal
* arrays
*/
typedef enum mali_pmm_event_id
{
MALI_PMM_EVENT_OS_POWER_UP = 0, /**< OS power up event */
MALI_PMM_EVENT_OS_POWER_DOWN = 1, /**< OS power down event */
MALI_PMM_EVENT_JOB_SCHEDULED = 2, /**< Job scheduled to run event */
MALI_PMM_EVENT_JOB_QUEUED = 3, /**< Job queued (but not run) event */
MALI_PMM_EVENT_JOB_FINISHED = 4, /**< Job finished event */
MALI_PMM_EVENT_TIMEOUT = 5, /**< Time out timer has expired */
MALI_PMM_EVENT_DVFS_PAUSE = 6, /**< Mali device pause event */
MALI_PMM_EVENT_DVFS_RESUME = 7, /**< Mali device resume event */
MALI_PMM_EVENT_UKS = 200, /**< Events from the user-side start here */
MALI_PMM_EVENT_UK_EXAMPLE = _MALI_PMM_EVENT_UK_EXAMPLE,
MALI_PMM_EVENT_INTERNALS = 1000,
MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK = 1001, /**< Internal power up acknowledgement */
MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK = 1002, /**< Internal power down acknowledgment */
} mali_pmm_event_id;
/** @brief Use this when the power up/down callbacks do not need any OS data. */
#define MALI_PMM_NO_OS_DATA 1
/* @brief Geometry and pixel processor identifiers for the PMM
*
* @note these match the ARM Mali 400 PMU hardware definitions, apart from the "SYSTEM"
*/
typedef enum mali_pmm_core_id_tag
{
MALI_PMM_CORE_SYSTEM = 0x00000000, /**< All of the Mali hardware */
MALI_PMM_CORE_GP = 0x00000001, /**< Mali GP2 */
MALI_PMM_CORE_L2 = 0x00000002, /**< Level 2 cache */
MALI_PMM_CORE_PP0 = 0x00000004, /**< Mali 200 pixel processor 0 */
MALI_PMM_CORE_PP1 = 0x00000008, /**< Mali 200 pixel processor 1 */
MALI_PMM_CORE_PP2 = 0x00000010, /**< Mali 200 pixel processor 2 */
MALI_PMM_CORE_PP3 = 0x00000020, /**< Mali 200 pixel processor 3 */
MALI_PMM_CORE_PP_ALL = 0x0000003C /**< Mali 200 pixel processors 0-3 */
} mali_pmm_core_id;
/* @brief PMM bitmask of mali_pmm_core_ids
*/
typedef u32 mali_pmm_core_mask;
/* @brief PMM event timestamp type
*/
typedef u32 mali_pmm_timestamp;
/** @brief power management event message struct
*/
typedef struct _mali_pmm_message
{
mali_pmm_event_id id; /**< event id */
mali_pmm_message_data data; /**< specific data associated with the event */
mali_pmm_timestamp ts; /**< timestamp the event was placed in the event queue */
} mali_pmm_message_t;
/** @brief the state of the power management module.
*/
/* These must match up with the pmm_trace_state array */
typedef enum mali_pmm_state_tag
{
MALI_PMM_STATE_UNAVAILABLE = 0, /**< PMM is not available */
MALI_PMM_STATE_SYSTEM_ON = 1, /**< All of the Mali hardware is on */
MALI_PMM_STATE_SYSTEM_OFF = 2, /**< All of the Mali hardware is off */
MALI_PMM_STATE_SYSTEM_TRANSITION = 3 /**< System is changing state */
} mali_pmm_state;
/** @brief a power management policy.
*/
/* These must match up with the pmm_trace_policy array */
typedef enum mali_pmm_policy_tag
{
MALI_PMM_POLICY_NONE = 0, /**< No policy */
MALI_PMM_POLICY_ALWAYS_ON = 1, /**< Always on policy */
MALI_PMM_POLICY_JOB_CONTROL = 2, /**< Job control policy */
MALI_PMM_POLICY_RUNTIME_JOB_CONTROL = 3 /**< Run time power management control policy */
} mali_pmm_policy;
/** @brief Function to report to the OS when the power down has finished
*
* @param data The event message data that initiated the power down
*/
void _mali_osk_pmm_power_down_done(mali_pmm_message_data data);
/** @brief Function to report to the OS when the power up has finished
*
* @param data The event message data that initiated the power up
*/
void _mali_osk_pmm_power_up_done(mali_pmm_message_data data);
/** @brief Function to report that DVFS operation done
*
* @param data The event message data
*/
void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data);
#if MALI_POWER_MGMT_TEST_SUITE
/** @brief Function to notify power management events
*
* @param data The event message data
*/
void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id event_id);
#endif
/** @brief Function to power up MALI
*
* @note powers up the MALI during MALI device driver is unloaded
*/
void malipmm_force_powerup( void );
/** @brief Function to power down MALI
*
* @note powers down the MALI during MALI device driver is unloaded
*/
void malipmm_force_powerdown( void );
/** @brief Function to report the OS that device is idle
*
* @note inform the OS that device is idle
*/
_mali_osk_errcode_t _mali_osk_pmm_dev_idle( void );
/** @brief Function to report the OS to activate device
*
* @note inform the os that device needs to be activated
*/
void _mali_osk_pmm_dev_activate( void );
/** @brief Queries the current state of the PMM software
*
* @note the state of the PMM can change after this call has returned
*
* @return the current PMM state value
*/
mali_pmm_state _mali_pmm_state( void );
/** @brief List of cores that are registered with the PMM
*
* This will return the cores that have been currently registered with the PMM,
* which is a bitwise OR of the mali_pmm_core_id_tags. A value of 0x0 means that
* there are no cores registered.
*
* @note the list of cores can change after this call has returned
*
* @return a bit mask representing all the cores that have been registered with the PMM
*/
mali_pmm_core_mask _mali_pmm_cores_list( void );
/** @brief List of cores that are powered up in the PMM
*
* This will return the subset of the cores that can be listed using mali_pmm_cores_
* list, that have power. It is a bitwise OR of the mali_pmm_core_id_tags. A value of
* 0x0 means that none of the cores registered are powered.
*
* @note the list of cores can change after this call has returned
*
* @return a bit mask representing all the cores that are powered up
*/
mali_pmm_core_mask _mali_pmm_cores_powered( void );
/** @brief List of power management policies that are supported by the PMM
*
* Given an empty array of policies - policy_list - which contains the number
* of entries as specified by - policy_list_size, this function will populate
* the list with the available policies. If the policy_list is too small for
* all the policies then only policy_list_size entries will be returned. If the
* policy_list is bigger than the number of available policies then, the extra
* entries will be set to MALI_PMM_POLICY_NONE.
* The function will also update available_policies with the number of policies
* that are available, even if it exceeds the policy_list_size.
* The function will succeed if all policies could be returned, else it will
* fail if none or only a subset of policies could be returned.
* The function will also fail if no policy_list is supplied, though
* available_policies is optional.
*
* @note this is a STUB function and is not yet implemented
*
* @param policy_list_size is the number of policies that can be returned in
* the policy_list argument
* @param policy_list is an array of policies that should be populated with
* the list of policies that are supported by the PMM
* @param policies_available optional argument, if non-NULL will be set to the
* number of policies available
* @return _MALI_OSK_ERR_OK if the policies could be listed, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t _mali_pmm_list_policies(
u32 policy_list_size,
mali_pmm_policy *policy_list,
u32 *policies_available );
/** @brief Set the power management policy in the PMM
*
* Given a valid supported policy, this function will change the PMM to use
* this new policy
* The function will fail if the policy given is invalid or unsupported.
*
* @note this is a STUB function and is not yet implemented
*
* @param policy the new policy to be set
* @return _MALI_OSK_ERR_OK if the policy could be set, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy );
/** @brief Get the current power management policy in the PMM
*
* Given a pointer to a policy data type, this function will return the current
* policy that is in effect for the PMM. This maybe out of date if there is a
* pending set policy call that has not been serviced.
* The function will fail if the policy given is NULL.
*
* @note the policy of the PMM can change after this call has returned
*
* @param policy a pointer to a policy that can be updated to the current
* policy
* @return _MALI_OSK_ERR_OK if the policy could be returned, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy );
#if MALI_PMM_TRACE
/** @brief Indicates when a hardware state change occurs in the PMM
*
* @param old a mask of the cores indicating the previous state of the cores
* @param newstate a mask of the cores indicating the new current state of the cores
*/
void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate );
/** @brief Indicates when a state change occurs in the PMM
*
* @param old the previous state for the PMM
* @param newstate the new current state of the PMM
*/
void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate );
/** @brief Indicates when a policy change occurs in the PMM
*
* @param old the previous policy for the PMM
* @param newpolicy the new current policy of the PMM
*/
void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy );
/** @brief Records when an event message is read by the event system
*
* @param event the message details
* @param received MALI_TRUE when the message is received by the PMM, else it is being sent
*/
void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received );
#endif /* MALI_PMM_TRACE */
/** @brief Dumps the current state of OS PMM thread
*/
#if MALI_STATE_TRACKING
u32 mali_pmm_dump_os_thread_state( char *buf, u32 size );
#endif /* MALI_STATE_TRACKING */
/** @} */ /* end group pmmapi */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_H__ */

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy.c
* Implementation of the common routines for power management module
* policies
*/
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_pmm.h"
#include "mali_pmm_system.h"
#include "mali_pmm_state.h"
#include "mali_pmm_policy.h"
#include "mali_pmm_policy_alwayson.h"
#include "mali_pmm_policy_jobcontrol.h"
/* Call back function for timer expiration */
static void pmm_policy_timer_callback( void *arg );
_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id )
{
MALI_DEBUG_ASSERT_POINTER(pptimer);
/* All values get 0 as default */
_mali_osk_memset(pptimer, 0, sizeof(*pptimer));
pptimer->timer = _mali_osk_timer_init();
if( pptimer->timer )
{
_mali_osk_timer_setcallback( pptimer->timer, pmm_policy_timer_callback, (void *)pptimer );
pptimer->timeout = timeout;
pptimer->event_id = id;
MALI_SUCCESS;
}
return _MALI_OSK_ERR_FAULT;
}
static void pmm_policy_timer_callback( void *arg )
{
_pmm_policy_timer_t *pptimer = (_pmm_policy_timer_t *)arg;
MALI_DEBUG_ASSERT_POINTER(pptimer);
MALI_DEBUG_ASSERT( pptimer->set );
/* Set timer expired and flag there is a policy to check */
pptimer->expired = MALI_TRUE;
malipmm_set_policy_check();
}
void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer )
{
MALI_DEBUG_ASSERT_POINTER(pptimer);
_mali_osk_timer_del( pptimer->timer );
_mali_osk_timer_term( pptimer->timer );
pptimer->timer = NULL;
}
mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer )
{
MALI_DEBUG_ASSERT_POINTER(pptimer);
MALI_DEBUG_ASSERT_POINTER(pptimer->timer);
if( !(pptimer->set) )
{
pptimer->set = MALI_TRUE;
pptimer->expired = MALI_FALSE;
pptimer->start = _mali_osk_time_tickcount();
_mali_osk_timer_add( pptimer->timer, pptimer->timeout );
return MALI_TRUE;
}
return MALI_FALSE;
}
mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer )
{
MALI_DEBUG_ASSERT_POINTER(pptimer);
MALI_DEBUG_ASSERT_POINTER(pptimer->timer);
if( pptimer->set )
{
_mali_osk_timer_del( pptimer->timer );
pptimer->set = MALI_FALSE;
pptimer->expired = MALI_FALSE;
return MALI_TRUE;
}
return MALI_FALSE;
}
mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer )
{
MALI_DEBUG_ASSERT_POINTER(pptimer);
if( pptimer->expired )
{
_mali_uk_pmm_message_s event = {
NULL,
MALI_PMM_EVENT_TIMEOUT, /* Assume timeout id, but set it below */
0 };
event.id = pptimer->event_id;
event.data = (mali_pmm_message_data)pptimer->start;
/* Don't need to do any other notification with this timer */
pptimer->expired = MALI_FALSE;
/* Unset timer so it is free to be set again */
pptimer->set = MALI_FALSE;
_mali_ukk_pmm_event_message( &event );
return MALI_TRUE;
}
return MALI_FALSE;
}
mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start )
{
return (_mali_osk_time_after( other_start, timer_start ) == 0);
}
_mali_osk_errcode_t pmm_policy_init(_mali_pmm_internal_state_t *pmm)
{
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER(pmm);
switch( pmm->policy )
{
case MALI_PMM_POLICY_ALWAYS_ON:
{
err = pmm_policy_init_always_on();
}
break;
case MALI_PMM_POLICY_JOB_CONTROL:
{
err = pmm_policy_init_job_control(pmm);
}
break;
case MALI_PMM_POLICY_NONE:
default:
err = _MALI_OSK_ERR_FAULT;
}
return err;
}
void pmm_policy_term(_mali_pmm_internal_state_t *pmm)
{
MALI_DEBUG_ASSERT_POINTER(pmm);
switch( pmm->policy )
{
case MALI_PMM_POLICY_ALWAYS_ON:
{
pmm_policy_term_always_on();
}
break;
case MALI_PMM_POLICY_JOB_CONTROL:
{
pmm_policy_term_job_control();
}
break;
case MALI_PMM_POLICY_NONE:
default:
MALI_PRINT_ERROR( ("PMM: Invalid policy terminated %d\n", pmm->policy) );
}
}
_mali_osk_errcode_t pmm_policy_process(_mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event)
{
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(event);
switch( pmm->policy )
{
case MALI_PMM_POLICY_ALWAYS_ON:
{
err = pmm_policy_process_always_on( pmm, event );
}
break;
case MALI_PMM_POLICY_JOB_CONTROL:
{
err = pmm_policy_process_job_control( pmm, event );
}
break;
case MALI_PMM_POLICY_NONE:
default:
err = _MALI_OSK_ERR_FAULT;
}
return err;
}
void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
switch( pmm->policy )
{
case MALI_PMM_POLICY_JOB_CONTROL:
{
pmm_policy_check_job_control();
}
break;
default:
/* Nothing needs to be done */
break;
}
}
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy.h
* Defines the power management module policies
*/
#ifndef __MALI_PMM_POLICY_H__
#define __MALI_PMM_POLICY_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup pmmapi Power Management Module APIs
*
* @{
*
* @defgroup pmmapi_policy Power Management Module Policies
*
* @{
*/
/** @brief Generic timer for use with policies
*/
typedef struct _pmm_policy_timer
{
u32 timeout; /**< Timeout for this timer in ticks */
mali_pmm_event_id event_id; /**< Event id that will be raised when timer expires */
_mali_osk_timer_t *timer; /**< Timer */
mali_bool set; /**< Timer set */
mali_bool expired; /**< Timer expired - event needs to be raised */
u32 start; /**< Timer start ticks */
} _pmm_policy_timer_t;
/** @brief Policy timer initialization
*
* This will create a timer for use in policies, but won't start it
*
* @param pptimer An empty timer structure to be initialized
* @param timeout Timeout in ticks for the timer
* @param id Event id that will be raised on timeout
* @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id );
/** @brief Policy timer termination
*
* This will clean up a timer that was previously used in policies, it
* will also stop it if started
*
* @param pptimer An initialized timer structure to be terminated
*/
void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer );
/** @brief Policy timer start
*
* This will start a previously created timer for use in policies
* When the timer expires after the initialized timeout it will raise
* a PMM event of the event id given on initialization
* As data for the event it will pass the start time of the timer
*
* @param pptimer A previously initialized policy timer
* @return MALI_TRUE if the timer was started, MALI_FALSE if it is already started
*/
mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer );
/** @brief Policy timer stop
*
* This will stop a previously created timer for use in policies
*
* @param pptimer A previously started policy timer
* @return MALI_TRUE if the timer was stopped, MALI_FALSE if it is already stopped
*/
mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer );
/** @brief Policy timer stop
*
* This raise an event for an expired timer
*
* @param pptimer An expired policy timer
* @return MALI_TRUE if an event was raised, else MALI_FALSE
*/
mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer );
/** @brief Policy timer valid checker
*
* This will check that a timer was started after a given time
*
* @param timer_start Time the timer was started
* @param other_start Time when another event or action occurred
* @return MALI_TRUE if the timer was started after the other time, else MALI_FALSE
*/
mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start );
/** @brief Common policy initialization
*
* This will initialize the current policy
*
* @note Any previously initialized policy should be terminated first
*
* @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_init( _mali_pmm_internal_state_t *pmm );
/** @brief Common policy termination
*
* This will terminate the current policy.
* @note This can be called when a policy has not been initialized
*/
void pmm_policy_term( _mali_pmm_internal_state_t *pmm );
/** @brief Common policy state changer
*
* Given the next available event message, this routine passes it to
* the current policy for processing
*
* @param pmm internal PMM state
* @param event PMM event to process
* @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_process( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
/** @brief Common policy checker
*
* If a policy timer fires then this function will be called to
* allow the policy to take the correct action
*
* @param pmm internal PMM state
*/
void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm );
/** @} */ /* End group pmmapi_policy */
/** @} */ /* End group pmmapi */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_POLICY_H__ */

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy_alwayson.c
* Implementation of the power management module policy - always on
*/
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_pmm.h"
#include "mali_pmm_system.h"
#include "mali_pmm_state.h"
#include "mali_pmm_policy.h"
#include "mali_pmm_policy_alwayson.h"
_mali_osk_errcode_t pmm_policy_init_always_on(void)
{
/* Nothing to set up */
MALI_SUCCESS;
}
void pmm_policy_term_always_on(void)
{
/* Nothing to tear down */
}
_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(event);
switch( event->id )
{
case MALI_PMM_EVENT_OS_POWER_DOWN:
/* We aren't going to do anything, but signal so we don't block the OS
* NOTE: This may adversely affect any jobs Mali is currently running
*/
_mali_osk_pmm_power_down_done( event->data );
break;
case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
/* Not expected in this policy */
MALI_DEBUG_ASSERT( MALI_FALSE );
break;
case MALI_PMM_EVENT_OS_POWER_UP:
/* Nothing to do */
_mali_osk_pmm_power_up_done( event->data );
break;
case MALI_PMM_EVENT_JOB_SCHEDULED:
case MALI_PMM_EVENT_JOB_QUEUED:
case MALI_PMM_EVENT_JOB_FINISHED:
/* Nothing to do - we are always on */
break;
case MALI_PMM_EVENT_TIMEOUT:
/* Not expected in this policy */
MALI_DEBUG_ASSERT( MALI_FALSE );
break;
default:
MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
}
MALI_SUCCESS;
}
#endif

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy_alwayson.h
* Defines the power management module policy for always on
*/
#ifndef __MALI_PMM_POLICY_ALWAYSON_H__
#define __MALI_PMM_POLICY_ALWAYSON_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup pmmapi_policy Power Management Module Policies
*
* @{
*/
/** @brief Always on policy initialization
*
* @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_init_always_on(void);
/** @brief Always on policy termination
*/
void pmm_policy_term_always_on(void);
/** @brief Always on policy state changer
*
* Given the next available event message, this routine processes it
* for the policy and changes state as needed.
*
* Always on policy will ignore all events and keep the Mali cores on
* all the time
*
* @param pmm internal PMM state
* @param event PMM event to process
* @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
/** @} */ /* End group pmmapi_policies */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_POLICY_ALWAYSON_H__ */

View File

@@ -0,0 +1,461 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy_jobcontrol.c
* Implementation of the power management module policy - job control
*/
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_platform.h"
#include "mali_pmm.h"
#include "mali_pmm_system.h"
#include "mali_pmm_state.h"
#include "mali_pmm_policy.h"
#include "mali_pmm_policy_jobcontrol.h"
typedef struct _pmm_policy_data_job_control
{
_pmm_policy_timer_t latency; /**< Latency timeout timer for all cores */
u32 core_active_start; /**< Last time a core was set to active */
u32 timeout; /**< Timeout in ticks for latency timer */
} _pmm_policy_data_job_control_t;
/* @ brief Local data for this policy
*/
static _pmm_policy_data_job_control_t *data_job_control = NULL;
/* @brief Set up the timeout if it hasn't already been set and if there are active cores */
static void job_control_timeout_setup( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(pptimer);
/* Do we have an inactivity time out and some powered cores? */
if( pptimer->timeout > 0 && pmm->cores_powered != 0 )
{
/* Is the system idle and all the powered cores are idle? */
if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->cores_idle == pmm->cores_powered )
{
if( pmm_policy_timer_start(pptimer) )
{
MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Setting in-activity latency timer\n") );
}
}
else
{
/* We are not idle so there is no need for an inactivity timer
*/
if( pmm_policy_timer_stop(pptimer) )
{
MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Removing in-activity latency timer\n") );
}
}
}
}
/* @brief Check the validity of the timeout - and if there is one set */
static mali_bool job_control_timeout_valid( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer, u32 timer_start )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(pptimer);
/* Not a valid timer! */
if( pptimer->timeout == 0 ) return MALI_FALSE;
/* Are some cores powered and are they all idle? */
if( (pmm->cores_powered != 0) && (pmm->cores_idle == pmm->cores_powered) )
{
/* Has latency timeout started after the last core was active? */
if( pmm_policy_timer_valid( timer_start, data_job_control->core_active_start ) )
{
return MALI_TRUE;
}
else
{
MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - out of date\n") );
}
}
else
{
if( pmm->cores_powered == 0 )
{
MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores already off\n") );
}
else
{
MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores active\n") );
}
}
return MALI_FALSE;
}
_mali_osk_errcode_t pmm_policy_init_job_control( _mali_pmm_internal_state_t *pmm )
{
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER( pmm );
MALI_DEBUG_ASSERT( data_job_control == NULL );
data_job_control = (_pmm_policy_data_job_control_t *) _mali_osk_malloc(sizeof(*data_job_control));
MALI_CHECK_NON_NULL( data_job_control, _MALI_OSK_ERR_NOMEM );
data_job_control->core_active_start = _mali_osk_time_tickcount();
data_job_control->timeout = MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT;
err = pmm_policy_timer_init( &data_job_control->latency, data_job_control->timeout, MALI_PMM_EVENT_TIMEOUT );
if( err != _MALI_OSK_ERR_OK )
{
_mali_osk_free( data_job_control );
data_job_control = NULL;
return err;
}
/* Start the latency timeout */
job_control_timeout_setup( pmm, &data_job_control->latency );
MALI_SUCCESS;
}
void pmm_policy_term_job_control(void)
{
if( data_job_control != NULL )
{
pmm_policy_timer_term( &data_job_control->latency );
_mali_osk_free( data_job_control );
data_job_control = NULL;
}
}
static void pmm_policy_job_control_job_queued( _mali_pmm_internal_state_t *pmm )
{
mali_pmm_core_mask cores;
mali_pmm_core_mask cores_subset;
/* Make sure that all cores are powered in this
* simple policy
*/
cores = pmm->cores_registered;
cores_subset = pmm_cores_to_power_up( pmm, cores );
if( cores_subset != 0 )
{
/* There are some cores that need powering up */
if( !pmm_invoke_power_up( pmm ) )
{
/* Need to wait until finished */
pmm->status = MALI_PMM_STATUS_POLICY_POWER_UP;
}
}
}
_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
{
mali_pmm_core_mask cores;
mali_pmm_core_mask cores_subset;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(event);
MALI_DEBUG_ASSERT_POINTER(data_job_control);
MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process start - status=%d\n", pmm->status) );
/* Mainly the data is the cores */
cores = pmm_cores_from_event_data( pmm, event );
#if MALI_STATE_TRACKING
pmm->mali_last_pmm_status = pmm->status;
#endif /* MALI_STATE_TRACKING */
switch( pmm->status )
{
/**************** IDLE ****************/
case MALI_PMM_STATUS_IDLE:
switch( event->id )
{
case MALI_PMM_EVENT_OS_POWER_UP:
/* Not expected in this state */
break;
case MALI_PMM_EVENT_JOB_SCHEDULED:
/* Update idle cores to indicate active - remove these! */
pmm_cores_set_active( pmm, cores );
/* Remember when this happened */
data_job_control->core_active_start = event->ts;
#if MALI_POWER_MGMT_TEST_SUITE
_mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_SCHEDULED);
#endif
/*** FALL THROUGH to QUEUED to check POWER UP ***/
case MALI_PMM_EVENT_JOB_QUEUED:
pmm_policy_job_control_job_queued( pmm );
#if MALI_POWER_MGMT_TEST_SUITE
_mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_QUEUED);
#endif
break;
case MALI_PMM_EVENT_DVFS_PAUSE:
cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE );
if ( cores_subset != 0 )
{
if ( !pmm_power_down_okay( pmm ) )
{
pmm->is_dvfs_active = 1;
pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN;
pmm_save_os_event_data( pmm, event->data );
break;
}
}
pmm->status = MALI_PMM_STATUS_DVFS_PAUSE;
_mali_osk_pmm_dvfs_operation_done(0);
break;
case MALI_PMM_EVENT_OS_POWER_DOWN:
/* Need to power down all cores even if we need to wait for them */
cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE );
if( cores_subset != 0 )
{
/* There are some cores that need powering down */
if( !pmm_invoke_power_down( pmm ) )
{
/* We need to wait until they are idle */
pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN;
/* Save the OS data to respond later */
pmm_save_os_event_data( pmm, event->data );
/* Exit this case - as we have to wait */
break;
}
}
/* Set waiting status */
pmm->status = MALI_PMM_STATUS_OS_WAITING;
/* All cores now down - respond to OS power event */
_mali_osk_pmm_power_down_done( event->data );
break;
case MALI_PMM_EVENT_JOB_FINISHED:
/* Update idle cores - add these! */
pmm_cores_set_idle( pmm, cores );
#if MALI_POWER_MGMT_TEST_SUITE
_mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_FINISHED);
#endif
if( data_job_control->timeout > 0 )
{
/* Wait for time out to fire */
break;
}
/* For job control policy - turn off all cores */
cores = pmm->cores_powered;
/*** FALL THROUGH to TIMEOUT TEST as NO TIMEOUT ***/
case MALI_PMM_EVENT_TIMEOUT:
/* Main job control policy - turn off cores after inactivity */
if( job_control_timeout_valid( pmm, &data_job_control->latency, (u32)event->data ) )
{
/* Valid timeout of inactivity - so find out if we can power down
* immedately - if we can't then this means the cores are still in fact
* active
*/
cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_TRUE );
if( cores_subset != 0 )
{
/* Check if we can really power down, if not then we are not
* really in-active
*/
if( !pmm_invoke_power_down( pmm ) )
{
pmm_power_down_cancel( pmm );
}
}
/* else there are no cores powered up! */
}
#if MALI_POWER_MGMT_TEST_SUITE
_mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_TIMEOUT);
#endif
break;
default:
/* Unexpected event */
MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
}
break;
/******************DVFS PAUSE**************/
case MALI_PMM_STATUS_DVFS_PAUSE:
switch ( event->id )
{
case MALI_PMM_EVENT_DVFS_RESUME:
if ( pmm->cores_powered != 0 )
{
pmm->cores_ack_down =0;
pmm_power_down_cancel( pmm );
pmm->status = MALI_PMM_STATUS_IDLE;
}
else
{
pmm_policy_job_control_job_queued( pmm );
}
_mali_osk_pmm_dvfs_operation_done( 0 );
break;
case MALI_PMM_EVENT_OS_POWER_DOWN:
/* Set waiting status */
pmm->status = MALI_PMM_STATUS_OS_WAITING;
if ( pmm->cores_powered != 0 )
{
if ( pmm_invoke_power_down( pmm ) )
{
_mali_osk_pmm_power_down_done( 0 );
break;
}
}
_mali_osk_pmm_power_down_done( 0 );
break;
default:
break;
}
break;
/**************** POWER UP ****************/
case MALI_PMM_STATUS_OS_POWER_UP:
case MALI_PMM_STATUS_POLICY_POWER_UP:
switch( event->id )
{
case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
/* Make sure cores powered off equal what we expect */
MALI_DEBUG_ASSERT( cores == pmm->cores_pend_up );
pmm_cores_set_up_ack( pmm, cores );
if( pmm_invoke_power_up( pmm ) )
{
if( pmm->status == MALI_PMM_STATUS_OS_POWER_UP )
{
/* Get the OS data and respond to the power up */
_mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) );
}
pmm->status = MALI_PMM_STATUS_IDLE;
}
break;
default:
/* Unexpected event */
MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
}
break;
/**************** POWER DOWN ****************/
case MALI_PMM_STATUS_OS_POWER_DOWN:
case MALI_PMM_STATUS_POLICY_POWER_DOWN:
switch( event->id )
{
case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
pmm_cores_set_down_ack( pmm, cores );
if ( pmm->is_dvfs_active == 1 )
{
if( pmm_power_down_okay( pmm ) )
{
pmm->is_dvfs_active = 0;
pmm->status = MALI_PMM_STATUS_DVFS_PAUSE;
_mali_osk_pmm_dvfs_operation_done( pmm_retrieve_os_event_data( pmm ) );
}
break;
}
/* Now check if we can power down */
if( pmm_invoke_power_down( pmm ) )
{
if( pmm->status == MALI_PMM_STATUS_OS_POWER_DOWN )
{
/* Get the OS data and respond to the power down */
_mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) );
}
pmm->status = MALI_PMM_STATUS_OS_WAITING;
}
break;
default:
/* Unexpected event */
MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
}
break;
case MALI_PMM_STATUS_OS_WAITING:
switch( event->id )
{
case MALI_PMM_EVENT_OS_POWER_UP:
cores_subset = pmm_cores_to_power_up( pmm, cores );
if( cores_subset != 0 )
{
/* There are some cores that need powering up */
if( !pmm_invoke_power_up( pmm ) )
{
/* Need to wait until power up complete */
pmm->status = MALI_PMM_STATUS_OS_POWER_UP;
/* Save the OS data to respond later */
pmm_save_os_event_data( pmm, event->data );
/* Exit this case - as we have to wait */
break;
}
}
pmm->status = MALI_PMM_STATUS_IDLE;
/* All cores now up - respond to OS power up event */
_mali_osk_pmm_power_up_done( event->data );
break;
default:
/* All other messages are ignored in this state */
break;
}
break;
default:
/* Unexpected state */
MALI_ERROR(_MALI_OSK_ERR_FAULT);
}
/* Set in-activity latency timer - if required */
job_control_timeout_setup( pmm, &data_job_control->latency );
/* Update the PMM state */
pmm_update_system_state( pmm );
#if MALI_STATE_TRACKING
pmm->mali_new_event_status = event->id;
#endif /* MALI_STATE_TRACKING */
MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process end - status=%d and event=%d\n", pmm->status,event->id) );
MALI_SUCCESS;
}
void pmm_policy_check_job_control()
{
MALI_DEBUG_ASSERT_POINTER(data_job_control);
/* Latency timer must have expired raise the event */
pmm_policy_timer_raise_event(&data_job_control->latency);
}
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_policy.h
* Defines the power management module policies
*/
#ifndef __MALI_PMM_POLICY_JOBCONTROL_H__
#define __MALI_PMM_POLICY_JOBCONTROL_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup pmmapi_policy Power Management Module Policies
*
* @{
*/
/** @brief The jobcontrol policy inactivity latency timeout (in ticks)
* before the hardware is switched off
*
* @note Setting this low whilst tracing or producing debug output can
* cause alot of timeouts to fire which can affect the PMM behaviour
*/
#define MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT 50
/** @brief Job control policy initialization
*
* @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_init_job_control(_mali_pmm_internal_state_t *pmm);
/** @brief Job control policy termination
*/
void pmm_policy_term_job_control(void);
/** @brief Job control policy state changer
*
* Given the next available event message, this routine processes it
* for the policy and changes state as needed.
*
* Job control policy depends on events from the Mali cores, and will
* power down all cores after an inactivity latency timeout. It will
* power the cores back on again when a job is scheduled to run.
*
* @param pmm internal PMM state
* @param event PMM event to process
* @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
* _mali_osk_errcode_t otherwise.
*/
_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
/** @brief Job control policy checker
*
* The latency timer has fired and we need to raise the correct event to
* handle it
*
* @param pmm internal PMM state
*/
void pmm_policy_check_job_control(void);
/** @} */ /* End group pmmapi_policy */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_POLICY_JOBCONTROL_H__ */

View File

@@ -0,0 +1,718 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_state.c
* Implementation of the power management module internal state
*/
#if USING_MALI_PMM
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_subsystem.h"
#include "mali_pmm.h"
#include "mali_pmm_state.h"
#include "mali_pmm_system.h"
#include "mali_kernel_core.h"
#include "mali_platform.h"
#define SIZEOF_CORES_LIST 6
/* NOTE: L2 *MUST* be first on the list so that it
* is correctly powered on first and powered off last
*/
static mali_pmm_core_id cores_list[] = { MALI_PMM_CORE_L2,
MALI_PMM_CORE_GP,
MALI_PMM_CORE_PP0,
MALI_PMM_CORE_PP1,
MALI_PMM_CORE_PP2,
MALI_PMM_CORE_PP3 };
void pmm_update_system_state( _mali_pmm_internal_state_t *pmm )
{
mali_pmm_state state;
MALI_DEBUG_ASSERT_POINTER(pmm);
if( pmm->cores_registered == 0 )
{
state = MALI_PMM_STATE_UNAVAILABLE;
}
else if( pmm->cores_powered == 0 )
{
state = MALI_PMM_STATE_SYSTEM_OFF;
}
else if( pmm->cores_powered == pmm->cores_registered )
{
state = MALI_PMM_STATE_SYSTEM_ON;
}
else
{
/* Some other state where not everything is on or off */
state = MALI_PMM_STATE_SYSTEM_TRANSITION;
}
#if MALI_PMM_TRACE
_mali_pmm_trace_state_change( pmm->state, state );
#endif
pmm->state = state;
}
mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
{
mali_pmm_core_mask cores;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_DEBUG_ASSERT_POINTER(event);
switch( event->id )
{
case MALI_PMM_EVENT_OS_POWER_UP:
case MALI_PMM_EVENT_OS_POWER_DOWN:
/* All cores - the system */
cores = pmm->cores_registered;
break;
case MALI_PMM_EVENT_JOB_SCHEDULED:
case MALI_PMM_EVENT_JOB_QUEUED:
case MALI_PMM_EVENT_JOB_FINISHED:
case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
/* Currently the main event data is only the cores
* for these messages
*/
cores = (mali_pmm_core_mask)event->data;
if( cores == MALI_PMM_CORE_SYSTEM )
{
cores = pmm->cores_registered;
}
else if( cores == MALI_PMM_CORE_PP_ALL )
{
/* Get the subset of registered PP cores */
cores = (pmm->cores_registered & MALI_PMM_CORE_PP_ALL);
}
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
break;
default:
/* Assume timeout messages - report cores still powered */
cores = pmm->cores_powered;
break;
}
return cores;
}
mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
{
mali_pmm_core_mask cores_subset;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
/* Check that cores aren't pending power down when asked for power up */
MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
cores_subset = (~(pmm->cores_powered) & cores);
if( cores_subset != 0 )
{
/* There are some cores that need powering up */
pmm->cores_pend_up = cores_subset;
}
return cores_subset;
}
mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only )
{
mali_pmm_core_mask cores_subset;
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
/* Check that cores aren't pending power up when asked for power down */
MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
cores_subset = (pmm->cores_powered & cores);
if( cores_subset != 0 )
{
int n;
volatile mali_pmm_core_mask *ppowered = &(pmm->cores_powered);
/* There are some cores that need powering up, but we may
* need to wait until they are idle
*/
for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
{
if( (cores_list[n] & cores_subset) != 0 )
{
/* Core is to be powered down */
pmm->cores_pend_down |= cores_list[n];
/* Can't hold the power lock, when acessing subsystem mutex via
* the core power call.
* Due to terminatation of driver requiring a subsystem mutex
* and then power lock held to unregister a core.
* This does mean that the following function could fail
* as the core is unregistered before we tell it to power
* down, but it does not matter as we are terminating
*/
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
/* Signal the core to power down
* If it is busy (not idle) it will set a pending power down flag
* (as long as we don't want to only immediately power down).
* If it isn't busy it will move out of the idle queue right
* away
*/
err = mali_core_signal_power_down( cores_list[n], immediate_only );
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* Re-read cores_subset in case it has changed */
cores_subset = (*ppowered & cores);
if( err == _MALI_OSK_ERR_OK )
{
/* We moved an idle core to the power down queue
* which means it is now acknowledged (if it is still
* registered)
*/
pmm->cores_ack_down |= (cores_list[n] & cores_subset);
}
else
{
MALI_DEBUG_ASSERT( err == _MALI_OSK_ERR_BUSY ||
(err == _MALI_OSK_ERR_FAULT &&
(*ppowered & cores_list[n]) == 0) );
/* If we didn't move a core - it must be active, so
* leave it pending, so we get an acknowledgement (when
* not in immediate only mode)
* Alternatively we are shutting down and the core has
* been unregistered
*/
}
}
}
}
return cores_subset;
}
void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm )
{
int n;
mali_pmm_core_mask pd, ad;
_mali_osk_errcode_t err;
volatile mali_pmm_core_mask *pregistered;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALIPMM_DEBUG_PRINT( ("PMM: Cancelling power down\n") );
pd = pmm->cores_pend_down;
ad = pmm->cores_ack_down;
/* Clear the pending cores so that they don't move to the off
* queue if they haven't already
*/
pmm->cores_pend_down = 0;
pmm->cores_ack_down = 0;
pregistered = &(pmm->cores_registered);
/* Power up all the pending power down cores - just so
* we make sure the system is in a known state, as a
* pending core might have sent an acknowledged message
* which hasn't been read yet.
*/
for( n = 0; n < SIZEOF_CORES_LIST; n++ )
{
if( (cores_list[n] & pd) != 0 )
{
/* Can't hold the power lock, when acessing subsystem mutex via
* the core power call.
* Due to terminatation of driver requiring a subsystem mutex
* and then power lock held to unregister a core.
* This does mean that the following power up function could fail
* as the core is unregistered before we tell it to power
* up, but it does not matter as we are terminating
*/
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
/* As we are cancelling - only move the cores back to the queue -
* no reset needed
*/
err = mali_core_signal_power_up( cores_list[n], MALI_TRUE );
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* Update pending list with the current registered cores */
pd &= (*pregistered);
if( err != _MALI_OSK_ERR_OK )
{
MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_BUSY &&
((cores_list[n] & ad) == 0)) ||
(err == _MALI_OSK_ERR_FAULT &&
(*pregistered & cores_list[n]) == 0) );
/* If we didn't power up a core - it must be active and
* hasn't actually tried to power down - this is expected
* for cores that haven't acknowledged
* Alternatively we are shutting down and the core has
* been unregistered
*/
}
}
}
/* Only used in debug builds */
MALI_IGNORE(ad);
}
mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
return ( pmm->cores_pend_down == pmm->cores_ack_down ? MALI_TRUE : MALI_FALSE );
}
mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm )
{
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER(pmm);
/* Check that cores are pending power down during power down invoke */
MALI_DEBUG_ASSERT( pmm->cores_pend_down != 0 );
/* Check that cores are not pending power up during power down invoke */
MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
if( !pmm_power_down_okay( pmm ) )
{
MALIPMM_DEBUG_PRINT( ("PMM: Waiting for cores to go idle for power off - 0x%08x / 0x%08x\n",
pmm->cores_pend_down, pmm->cores_ack_down) );
return MALI_FALSE;
}
else
{
#if !MALI_PMM_NO_PMU
err = mali_platform_powerdown( pmm->cores_pend_down );
#else
err = _MALI_OSK_ERR_OK;
#endif
if( err == _MALI_OSK_ERR_OK )
{
#if MALI_PMM_TRACE
mali_pmm_core_mask old_power = pmm->cores_powered;
#endif
/* Remove powered down cores from idle and powered list */
pmm->cores_powered &= ~(pmm->cores_pend_down);
pmm->cores_idle &= ~(pmm->cores_pend_down);
/* Reset pending/acknowledged status */
pmm->cores_pend_down = 0;
pmm->cores_ack_down = 0;
#if MALI_PMM_TRACE
_mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
#endif
}
else
{
MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power down cores - (0x%x) %s",
pmm->cores_pend_down, pmm_trace_get_core_name(pmm->cores_pend_down)) );
pmm->fatal_power_err = MALI_TRUE;
}
}
return MALI_TRUE;
}
mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
return ( pmm->cores_pend_up == pmm->cores_ack_up ? MALI_TRUE : MALI_FALSE );
}
mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm )
{
_mali_osk_errcode_t err;
MALI_DEBUG_ASSERT_POINTER(pmm);
/* Check that cores are pending power up during power up invoke */
MALI_DEBUG_ASSERT( pmm->cores_pend_up != 0 );
/* Check that cores are not pending power down during power up invoke */
MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
if( pmm_power_up_okay( pmm ) )
{
/* Power up has completed - sort out subsystem core status */
int n;
/* Use volatile to access, so that it is updated if any cores are unregistered */
volatile mali_pmm_core_mask *ppendup = &(pmm->cores_pend_up);
#if MALI_PMM_TRACE
mali_pmm_core_mask old_power = pmm->cores_powered;
#endif
/* Move cores into idle queues */
for( n = 0; n < SIZEOF_CORES_LIST; n++ )
{
if( (cores_list[n] & (*ppendup)) != 0 )
{
/* Can't hold the power lock, when acessing subsystem mutex via
* the core power call.
* Due to terminatation of driver requiring a subsystem mutex
* and then power lock held to unregister a core.
* This does mean that the following function could fail
* as the core is unregistered before we tell it to power
* up, but it does not matter as we are terminating
*/
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
if( err != _MALI_OSK_ERR_OK )
{
MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_FAULT &&
(*ppendup & cores_list[n]) == 0) );
/* We only expect this to fail when we are shutting down
* and the core has been unregistered
*/
}
}
}
/* Finished power up - add cores to idle and powered list */
pmm->cores_powered |= (*ppendup);
pmm->cores_idle |= (*ppendup);
/* Reset pending/acknowledge status */
pmm->cores_pend_up = 0;
pmm->cores_ack_up = 0;
#if MALI_PMM_TRACE
_mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
#endif
return MALI_TRUE;
}
else
{
#if !MALI_PMM_NO_PMU
/* Power up must now be done */
err = mali_platform_powerup( pmm->cores_pend_up );
#else
err = _MALI_OSK_ERR_OK;
#endif
if( err != _MALI_OSK_ERR_OK )
{
MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power up cores - (0x%x) %s",
pmm->cores_pend_up, pmm_trace_get_core_name(pmm->cores_pend_up)) );
pmm->fatal_power_err = MALI_TRUE;
}
else
{
/* TBD - Update core status immediately rather than use event message */
_mali_uk_pmm_message_s event = {
NULL,
MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK,
0 };
/* All the cores that were pending power up, have now completed power up */
event.data = pmm->cores_pend_up;
_mali_ukk_pmm_event_message( &event );
MALIPMM_DEBUG_PRINT( ("PMM: Sending ACK to power up") );
}
}
/* Always return false, as we need an interrupt to acknowledge
* when power up is complete
*/
return MALI_FALSE;
}
mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
pmm->cores_idle &= (~cores);
return pmm->cores_idle;
}
mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
pmm->cores_idle |= (cores);
return pmm->cores_idle;
}
mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
/* Check core is not pending a power down */
MALI_DEBUG_ASSERT( (pmm->cores_pend_down & cores) != 0 );
/* Check core has not acknowledged power down more than once */
MALI_DEBUG_ASSERT( (pmm->cores_ack_down & cores) == 0 );
pmm->cores_ack_down |= (cores);
return pmm->cores_ack_down;
}
void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm )
{
_mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
_mali_osk_notification_t *msg = NULL;
mali_pmm_status status;
MALI_DEBUG_ASSERT_POINTER(pmm);
MALIPMM_DEBUG_PRINT( ("PMM: Fatal Reset called") );
MALI_DEBUG_ASSERT( pmm->status != MALI_PMM_STATUS_OFF );
/* Reset the common status */
pmm->waiting = 0;
pmm->missed = 0;
pmm->fatal_power_err = MALI_FALSE;
pmm->no_events = 0;
pmm->check_policy = MALI_FALSE;
pmm->cores_pend_down = 0;
pmm->cores_pend_up = 0;
pmm->cores_ack_down = 0;
pmm->cores_ack_up = 0;
pmm->is_dvfs_active = 0;
#if MALI_PMM_TRACE
pmm->messages_sent = 0;
pmm->messages_received = 0;
pmm->imessages_sent = 0;
pmm->imessages_received = 0;
MALI_PRINT( ("PMM Trace: *** Fatal reset occurred ***") );
#endif
/* Set that we are unavailable whilst resetting */
pmm->state = MALI_PMM_STATE_UNAVAILABLE;
status = pmm->status;
pmm->status = MALI_PMM_STATUS_OFF;
/* We want all cores powered */
pmm->cores_powered = pmm->cores_registered;
/* The cores may not be idle, but this state will be rectified later */
pmm->cores_idle = pmm->cores_registered;
/* So power on any cores that are registered */
if( pmm->cores_registered != 0 )
{
int n;
volatile mali_pmm_core_mask *pregistered = &(pmm->cores_registered);
#if !MALI_PMM_NO_PMU
err = mali_platform_powerup( pmm->cores_registered );
#endif
if( err != _MALI_OSK_ERR_OK )
{
/* This is very bad as we can't even be certain the cores are now
* powered up
*/
MALI_PRINT_ERROR( ("PMM: Failed to perform PMM reset!\n") );
/* TBD driver exit? */
}
for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
{
if( (cores_list[n] & (*pregistered)) != 0 )
{
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 0;
#endif /* MALI_STATE_TRACKING */
MALI_PMM_UNLOCK(pmm);
/* Core is now active - so try putting it in the idle queue */
err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
MALI_PMM_LOCK(pmm);
#if MALI_STATE_TRACKING
pmm->mali_pmm_lock_acquired = 1;
#endif /* MALI_STATE_TRACKING */
/* We either succeeded, or we were not off anyway, or we have
* just be deregistered
*/
MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_OK) ||
(err == _MALI_OSK_ERR_BUSY) ||
(err == _MALI_OSK_ERR_FAULT &&
(*pregistered & cores_list[n]) == 0) );
}
}
}
/* Unblock any pending OS event */
if( status == MALI_PMM_STATUS_OS_POWER_UP )
{
/* Get the OS data and respond to the power up */
_mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) );
}
if( status == MALI_PMM_STATUS_OS_POWER_DOWN )
{
/* Get the OS data and respond to the power down
* NOTE: We are not powered down at this point due to power problems,
* so we are lying to the system, but something bad has already
* happened and we are trying unstick things
* TBD - Add busy loop to power down cores?
*/
_mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) );
}
/* Purge the event queues */
do
{
if( _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ) == _MALI_OSK_ERR_OK )
{
_mali_osk_notification_delete ( msg );
break;
}
} while (MALI_TRUE);
do
{
if( _mali_osk_notification_queue_dequeue( pmm->queue, &msg ) == _MALI_OSK_ERR_OK )
{
_mali_osk_notification_delete ( msg );
break;
}
} while (MALI_TRUE);
/* Return status/state to normal */
pmm->status = MALI_PMM_STATUS_IDLE;
pmm_update_system_state(pmm);
}
mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
{
MALI_DEBUG_ASSERT_POINTER(pmm);
MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
/* Check core is not pending a power up */
MALI_DEBUG_ASSERT( (pmm->cores_pend_up & cores) != 0 );
/* Check core has not acknowledged power up more than once */
MALI_DEBUG_ASSERT( (pmm->cores_ack_up & cores) == 0 );
pmm->cores_ack_up |= (cores);
return pmm->cores_ack_up;
}
void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data)
{
MALI_DEBUG_ASSERT_POINTER(pmm);
/* Check that there is no saved data */
MALI_DEBUG_ASSERT( pmm->os_data == 0 );
/* Can't store zero data - as retrieve check will fail */
MALI_DEBUG_ASSERT( data != 0 );
pmm->os_data = data;
}
mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm)
{
mali_pmm_message_data data;
MALI_DEBUG_ASSERT_POINTER(pmm);
/* Check that there is saved data */
MALI_DEBUG_ASSERT( pmm->os_data != 0 );
/* Get data, and clear the saved version */
data = pmm->os_data;
pmm->os_data = 0;
return data;
}
/* Create list of core names to look up
* We are doing it this way to overcome the need for
* either string allocation, or stack space, so we
* use constant strings instead
*/
typedef struct pmm_trace_corelist
{
mali_pmm_core_mask id;
const char *name;
} pmm_trace_corelist_t;
static pmm_trace_corelist_t pmm_trace_cores[] = {
{ MALI_PMM_CORE_SYSTEM, "SYSTEM" },
{ MALI_PMM_CORE_GP, "GP" },
{ MALI_PMM_CORE_L2, "L2" },
{ MALI_PMM_CORE_PP0, "PP0" },
{ MALI_PMM_CORE_PP1, "PP1" },
{ MALI_PMM_CORE_PP2, "PP2" },
{ MALI_PMM_CORE_PP3, "PP3" },
{ MALI_PMM_CORE_PP_ALL, "PP (all)" },
{ (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0),
"GP+L2+PP0" },
{ (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0),
"GP+PP0" },
{ (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
"GP+L2+PP0+PP1" },
{ (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
"GP+PP0+PP1" },
{ 0, NULL } /* Terminator of list */
};
const char *pmm_trace_get_core_name( mali_pmm_core_mask cores )
{
const char *dname = NULL;
int cl;
/* Look up name in corelist */
cl = 0;
while( pmm_trace_cores[cl].name != NULL )
{
if( pmm_trace_cores[cl].id == cores )
{
dname = pmm_trace_cores[cl].name;
break;
}
cl++;
}
if( dname == NULL )
{
/* We don't know a good short-hand for the configuration */
dname = "[multi-core]";
}
return dname;
}
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_state.h
* Defines the internal power management module state
*/
#ifndef __MALI_PMM_STATE_H__
#define __MALI_PMM_STATE_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup pmmapi Power Management Module APIs
*
* @{
*
* @defgroup pmmapi_state Power Management Module State
*
* @{
*/
/* Check that the subset is really a subset of cores */
#define MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( cores, subset ) \
MALI_DEBUG_ASSERT( ((~(cores)) & (subset)) == 0 )
/* Locking macros */
#define MALI_PMM_LOCK(pmm) \
_mali_osk_lock_wait( pmm->lock, _MALI_OSK_LOCKMODE_RW )
#define MALI_PMM_UNLOCK(pmm) \
_mali_osk_lock_signal( pmm->lock, _MALI_OSK_LOCKMODE_RW )
#define MALI_PMM_LOCK_TERM(pmm) \
_mali_osk_lock_term( pmm->lock )
/* Notification type for messages */
#define MALI_PMM_NOTIFICATION_TYPE 0
/** @brief Status of the PMM state machine
*/
typedef enum mali_pmm_status_tag
{
MALI_PMM_STATUS_IDLE, /**< PMM is waiting next event */
MALI_PMM_STATUS_POLICY_POWER_DOWN, /**< Policy initiated power down */
MALI_PMM_STATUS_POLICY_POWER_UP, /**< Policy initiated power down */
MALI_PMM_STATUS_OS_WAITING, /**< PMM is waiting for OS power up */
MALI_PMM_STATUS_OS_POWER_DOWN, /**< OS initiated power down */
MALI_PMM_STATUS_DVFS_PAUSE, /**< PMM DVFS Status Pause */
MALI_PMM_STATUS_OS_POWER_UP, /**< OS initiated power up */
MALI_PMM_STATUS_OFF, /**< PMM is not active */
} mali_pmm_status;
/** @brief Internal state of the PMM
*/
typedef struct _mali_pmm_internal_state
{
mali_pmm_status status; /**< PMM state machine */
mali_pmm_policy policy; /**< PMM policy */
mali_bool check_policy; /**< PMM policy needs checking */
mali_pmm_state state; /**< PMM state */
mali_pmm_core_mask cores_registered; /**< Bitmask of cores registered */
mali_pmm_core_mask cores_powered; /**< Bitmask of cores powered up */
mali_pmm_core_mask cores_idle; /**< Bitmask of cores idle */
mali_pmm_core_mask cores_pend_down; /**< Bitmask of cores pending power down */
mali_pmm_core_mask cores_pend_up; /**< Bitmask of cores pending power up */
mali_pmm_core_mask cores_ack_down; /**< Bitmask of cores acknowledged power down */
mali_pmm_core_mask cores_ack_up; /**< Bitmask of cores acknowledged power up */
_mali_osk_notification_queue_t *queue; /**< PMM event queue */
_mali_osk_notification_queue_t *iqueue; /**< PMM internal event queue */
_mali_osk_irq_t *irq; /**< PMM irq handler */
_mali_osk_lock_t *lock; /**< PMM lock */
mali_pmm_message_data os_data; /**< OS data sent via the OS events */
mali_bool pmu_initialized; /**< PMU initialized */
_mali_osk_atomic_t messages_queued; /**< PMM event messages queued */
u32 waiting; /**< PMM waiting events - due to busy */
u32 no_events; /**< PMM called to process when no events */
u32 missed; /**< PMM missed events due to OOM */
mali_bool fatal_power_err; /**< PMM has had a fatal power error? */
u32 is_dvfs_active; /**< PMM DVFS activity */
#if MALI_STATE_TRACKING
mali_pmm_status mali_last_pmm_status; /**< The previous PMM status */
mali_pmm_event_id mali_new_event_status;/**< The type of the last PMM event */
mali_bool mali_pmm_lock_acquired; /**< Is the PMM lock held somewhere or not */
#endif
#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
u32 messages_sent; /**< Total event messages sent */
u32 messages_received; /**< Total event messages received */
u32 imessages_sent; /**< Total event internal messages sent */
u32 imessages_received; /**< Total event internal messages received */
#endif
} _mali_pmm_internal_state_t;
/** @brief Sets that a policy needs a check before processing events
*
* A timer or something has expired that needs dealing with
*/
void malipmm_set_policy_check(void);
/** @brief Update the PMM externally viewable state depending on the current PMM internal state
*
* @param pmm internal PMM state
* @return MALI_TRUE if the timeout is valid, else MALI_FALSE
*/
void pmm_update_system_state( _mali_pmm_internal_state_t *pmm );
/** @brief Returns the core mask from the event data - if applicable
*
* @param pmm internal PMM state
* @param event event message to get the core mask from
* @return mask of cores that is relevant to this event message
*/
mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
/** @brief Sort out which cores need to be powered up from the given core mask
*
* All cores that can be powered up will be put into a pending state
*
* @param pmm internal PMM state
* @param cores mask of cores to check if they need to be powered up
* @return mask of cores that need to be powered up, this can be 0 if all cores
* are powered up already
*/
mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
/** @brief Sort out which cores need to be powered down from the given core mask
*
* All cores that can be powered down will be put into a pending state. If they
* can be powered down immediately they will also be acknowledged that they can be
* powered down. If the immediate_only flag is set, then only those cores that
* can be acknowledged for power down will be put into a pending state.
*
* @param pmm internal PMM state
* @param cores mask of cores to check if they need to be powered down
* @param immediate_only MALI_TRUE means that only cores that can power down now will
* be put into a pending state
* @return mask of cores that need to be powered down, this can be 0 if all cores
* are powered down already
*/
mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only );
/** @brief Cancel an invokation to power down (pmm_invoke_power_down)
*
* @param pmm internal PMM state
*/
void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm );
/** @brief Check if a call to invoke power down should succeed, or fail
*
* This will report MALI_FALSE if some of the cores are still active and need
* to acknowledge that they are ready to power down
*
* @param pmm internal PMM state
* @return MALI_TRUE if the pending cores to power down have acknowledged they
* can power down, else MALI_FALSE
*/
mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm );
/** @brief Try to make all the pending cores power down
*
* If all the pending cores have acknowledged they can power down, this will call the
* PMU power down function to turn them off
*
* @param pmm internal PMM state
* @return MALI_TRUE if the pending cores have been powered down, else MALI_FALSE
*/
mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm );
/** @brief Check if all the pending cores to power up have done so
*
* This will report MALI_FALSE if some of the cores are still powered off
* and have not acknowledged that they have powered up
*
* @param pmm internal PMM state
* @return MALI_TRUE if the pending cores to power up have acknowledged they
* are now powered up, else MALI_FALSE
*/
mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm );
/** @brief Try to make all the pending cores power up
*
* If all the pending cores have acknowledged they have powered up, this will
* make the cores start processing jobs again, else this will call the PMU
* power up function to turn them on, and the PMM is then expected to wait for an
* interrupt to acknowledge the power up
*
* @param pmm internal PMM state
* @return MALI_TRUE if the pending cores have been powered up, else MALI_FALSE
*/
mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm );
/** @brief Set the cores that are now active in the system
*
* Updates which cores are active and returns which cores are still idle
*
* @param pmm internal PMM state
* @param cores mask of cores to set to active
* @return mask of all the cores that are idle
*/
mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
/** @brief Set the cores that are now idle in the system
*
* Updates which cores are idle and returns which cores are still idle
*
* @param pmm internal PMM state
* @param cores mask of cores to set to idle
* @return mask of all the cores that are idle
*/
mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
/** @brief Set the cores that have acknowledged a pending power down
*
* Updates which cores have acknowledged the pending power down and are now ready
* to be turned off
*
* @param pmm internal PMM state
* @param cores mask of cores that have acknowledged the pending power down
* @return mask of all the cores that have acknowledged the power down
*/
mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
/** @brief Set the cores that have acknowledged a pending power up
*
* Updates which cores have acknowledged the pending power up and are now
* fully powered and ready to run jobs
*
* @param pmm internal PMM state
* @param cores mask of cores that have acknowledged the pending power up
* @return mask of all the cores that have acknowledged the power up
*/
mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
/** @brief Tries to reset the PMM and PMU hardware to a known state after any fatal issues
*
* This will try and make all the cores powered up and reset the PMM state
* to its initial state after core registration - all cores powered but not
* pending or active.
* All events in the event queues will be thrown away.
*
* @note: Any pending power down will be cancelled including the OS calling for power down
*/
void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm );
/** @brief Save the OS specific data for an OS power up/down event
*
* @param pmm internal PMM state
* @param data OS specific event data
*/
void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data);
/** @brief Retrieve the OS specific data for an OS power up/down event
*
* This will clear the stored OS data, as well as return it.
*
* @param pmm internal PMM state
* @return OS specific event data that was saved previously
*/
mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm);
/** @brief Get a human readable name for the cores in a core mask
*
* @param core the core mask
* @return string containing a name relating to the given core mask
*/
const char *pmm_trace_get_core_name( mali_pmm_core_mask core );
/** @} */ /* End group pmmapi_state */
/** @} */ /* End group pmmapi */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_STATE_H__ */

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_pmm_system.h
* Defines the power management module system functions
*/
#ifndef __MALI_PMM_SYSTEM_H__
#define __MALI_PMM_SYSTEM_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @addtogroup pmmapi Power Management Module APIs
*
* @{
*
* @defgroup pmmapi_system Power Management Module System Functions
*
* @{
*/
extern struct mali_kernel_subsystem mali_subsystem_pmm;
/** @brief Register a core with the PMM, which will power up
* the core
*
* @param core the core to register with the PMM
* @return error if the core cannot be powered up
*/
_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core );
/** @brief Unregister a core with the PMM
*
* @param core the core to unregister with the PMM
*/
void malipmm_core_unregister( mali_pmm_core_id core );
/** @brief Acknowledge that a power down is okay to happen
*
* A core should not be running a job, or be in the idle queue when this
* is called.
*
* @param core the core that can now be powered down
*/
void malipmm_core_power_down_okay( mali_pmm_core_id core );
/** @} */ /* End group pmmapi_system */
/** @} */ /* End group pmmapi */
#ifdef __cplusplus
}
#endif
#endif /* __MALI_PMM_H__ */

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_kernel_license.h
* Defines for the macro MODULE_LICENSE.
*/
#ifndef __MALI_KERNEL_LICENSE_H__
#define __MALI_KERNEL_LICENSE_H__
#ifdef __cplusplus
extern "C"
{
#endif
#define MALI_KERNEL_LINUX_LICENSE "GPL"
#define MALI_LICENSE_IS_GPL 1
#ifdef __cplusplus
}
#endif
#endif /* __MALI_KERNEL_LICENSE_H__ */

View File

@@ -0,0 +1,82 @@
/**
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_device_pause_resume.c
* Implementation of the Mali pause/resume functionality
*/
#if USING_MALI_PMM
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/module.h>
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_platform.h"
#include "mali_linux_pm.h"
#include "mali_device_pause_resume.h"
#include "mali_pmm.h"
#include "mali_kernel_license.h"
#ifdef CONFIG_PM
#if MALI_LICENSE_IS_GPL
/* Mali Pause Resume APIs */
int mali_dev_pause()
{
int err = 0;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if ((mali_dvfs_device_state == _MALI_DEVICE_SUSPEND) || (mali_device_state == _MALI_DEVICE_SUSPEND_IN_PROGRESS)
|| (mali_device_state == _MALI_DEVICE_SUSPEND)
#ifdef CONFIG_HAS_EARLYSUSPEND
|| (mali_device_state == _MALI_DEVICE_EARLYSUSPEND_DISABLE_FB))
#else
)
#endif
{
err = -EPERM;
}
if ((mali_dvfs_device_state == _MALI_DEVICE_RESUME) && (!err))
{
mali_device_suspend(MALI_PMM_EVENT_DVFS_PAUSE, &dvfs_pm_thread);
mali_dvfs_device_state = _MALI_DEVICE_SUSPEND;
}
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
EXPORT_SYMBOL(mali_dev_pause);
int mali_dev_resume()
{
int err = 0;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if ((mali_dvfs_device_state == _MALI_DEVICE_RESUME) || (mali_device_state == _MALI_DEVICE_SUSPEND_IN_PROGRESS)
|| (mali_device_state == _MALI_DEVICE_SUSPEND)
#ifdef CONFIG_HAS_EARLYSUSPEND
|| (mali_device_state == _MALI_DEVICE_EARLYSUSPEND_DISABLE_FB))
#else
)
#endif
{
err = -EPERM;
}
if (!err)
{
mali_device_resume(MALI_PMM_EVENT_DVFS_RESUME, &dvfs_pm_thread);
mali_dvfs_device_state = _MALI_DEVICE_RESUME;
}
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
EXPORT_SYMBOL(mali_dev_resume);
#endif /* MALI_LICENSE_IS_GPL */
#endif /* CONFIG_PM */
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_DEVICE_PAUSE_RESUME_H__
#define __MALI_DEVICE_PAUSE_RESUME_H__
#if USING_MALI_PMM
int mali_dev_pause(void);
int mali_dev_resume(void);
#endif /* USING_MALI_PMM */
#endif /* __MALI_DEVICE_PAUSE_RESUME_H__ */

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_IOCTL_H__
#define __MALI_KERNEL_IOCTL_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/fs.h> /* file system operations */
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @file mali_kernel_ioctl.h
* Interface to the Linux device driver.
* This file describes the interface needed to use the Linux device driver.
* Its interface is designed to used by the HAL implementation through a thin arch layer.
*/
/**
* ioctl commands
*/
#define MALI_IOC_BASE 0x82
#define MALI_IOC_CORE_BASE (_MALI_UK_CORE_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_MEMORY_BASE (_MALI_UK_MEMORY_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_PP_BASE (_MALI_UK_PP_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_GP_BASE (_MALI_UK_GP_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_PROFILING_BASE (_MALI_UK_PROFILING_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_VSYNC_BASE (_MALI_UK_VSYNC_SUBSYSTEM + MALI_IOC_BASE)
#define MALI_IOC_GET_SYSTEM_INFO_SIZE _IOR (MALI_IOC_CORE_BASE, _MALI_UK_GET_SYSTEM_INFO_SIZE, _mali_uk_get_system_info_s *)
#define MALI_IOC_GET_SYSTEM_INFO _IOR (MALI_IOC_CORE_BASE, _MALI_UK_GET_SYSTEM_INFO, _mali_uk_get_system_info_s *)
#define MALI_IOC_WAIT_FOR_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_WAIT_FOR_NOTIFICATION, _mali_uk_wait_for_notification_s *)
#define MALI_IOC_GET_API_VERSION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_API_VERSION, _mali_uk_get_api_version_s *)
#define MALI_IOC_POST_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_POST_NOTIFICATION, _mali_uk_post_notification_s *)
#define MALI_IOC_MEM_GET_BIG_BLOCK _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GET_BIG_BLOCK, _mali_uk_get_big_block_s *)
#define MALI_IOC_MEM_FREE_BIG_BLOCK _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_FREE_BIG_BLOCK, _mali_uk_free_big_block_s *)
#define MALI_IOC_MEM_INIT _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_INIT_MEM, _mali_uk_init_mem_s *)
#define MALI_IOC_MEM_TERM _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_TERM_MEM, _mali_uk_term_mem_s *)
#define MALI_IOC_MEM_MAP_EXT _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MAP_EXT_MEM, _mali_uk_map_external_mem_s *)
#define MALI_IOC_MEM_UNMAP_EXT _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_UNMAP_EXT_MEM, _mali_uk_unmap_external_mem_s *)
#define MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, _mali_uk_query_mmu_page_table_dump_size_s *)
#define MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_DUMP_MMU_PAGE_TABLE, _mali_uk_dump_mmu_page_table_s *)
#define MALI_IOC_MEM_ATTACH_UMP _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_ATTACH_UMP_MEM, _mali_uk_attach_ump_mem_s *)
#define MALI_IOC_MEM_RELEASE_UMP _IOW(MALI_IOC_MEMORY_BASE, _MALI_UK_RELEASE_UMP_MEM, _mali_uk_release_ump_mem_s *)
#define MALI_IOC_PP_START_JOB _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_START_JOB, _mali_uk_pp_start_job_s *)
#define MALI_IOC_PP_NUMBER_OF_CORES_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_NUMBER_OF_CORES, _mali_uk_get_pp_number_of_cores_s *)
#define MALI_IOC_PP_CORE_VERSION_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_CORE_VERSION, _mali_uk_get_pp_core_version_s * )
#define MALI_IOC_PP_ABORT_JOB _IOW (MALI_IOC_PP_BASE, _MALI_UK_PP_ABORT_JOB, _mali_uk_pp_abort_job_s * )
#define MALI_IOC_GP2_START_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_START_JOB, _mali_uk_gp_start_job_s *)
#define MALI_IOC_GP2_ABORT_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_ABORT_JOB, _mali_uk_gp_abort_job_s *)
#define MALI_IOC_GP2_NUMBER_OF_CORES_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_NUMBER_OF_CORES, _mali_uk_get_gp_number_of_cores_s *)
#define MALI_IOC_GP2_CORE_VERSION_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_CORE_VERSION, _mali_uk_get_gp_core_version_s *)
#define MALI_IOC_GP2_SUSPEND_RESPONSE _IOW (MALI_IOC_GP_BASE, _MALI_UK_GP_SUSPEND_RESPONSE,_mali_uk_gp_suspend_response_s *)
#define MALI_IOC_PROFILING_START _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_START, _mali_uk_profiling_start_s *)
#define MALI_IOC_PROFILING_ADD_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_ADD_EVENT, _mali_uk_profiling_add_event_s*)
#define MALI_IOC_PROFILING_STOP _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_STOP, _mali_uk_profiling_stop_s *)
#define MALI_IOC_PROFILING_GET_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_EVENT, _mali_uk_profiling_get_event_s *)
#define MALI_IOC_PROFILING_CLEAR _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_CLEAR, _mali_uk_profiling_clear_s *)
#define MALI_IOC_VSYNC_EVENT_REPORT _IOW (MALI_IOC_VSYNC_BASE, _MALI_UK_VSYNC_EVENT_REPORT, _mali_uk_vsync_event_report_s *)
#ifdef __cplusplus
}
#endif
#endif /* __MALI_KERNEL_IOCTL_H__ */

View File

@@ -0,0 +1,508 @@
/**
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
* Copyright (C) 2011 STMicroelectronics R&D Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_kernel_linux.c
* Implementation of the Linux device driver entrypoints
*/
#include <linux/module.h> /* kernel module definitions */
#include <linux/fs.h> /* file system operations */
#include <linux/cdev.h> /* character device definitions */
#include <linux/mm.h> /* memory manager definitions */
#include <asm/uaccess.h> /* user space access */
#include <linux/device.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
#include <linux/io.h>
/* the mali kernel subsystem types */
#include "mali_kernel_subsystem.h"
/* A memory subsystem always exists, so no need to conditionally include it */
#include "mali_kernel_common.h"
#include "mali_kernel_mem.h"
#include "mali_kernel_session_manager.h"
#include "mali_kernel_core.h"
#include "mali_osk.h"
#include "mali_kernel_linux.h"
#include "mali_ukk.h"
#include "mali_kernel_ioctl.h"
#include "mali_ukk_wrappers.h"
#include "mali_kernel_pm.h"
#include "mali_kernel_sysfs.h"
/* */
#include "mali_kernel_license.h"
/* Module parameter to control log level */
int mali_debug_level = 2;
module_param(mali_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
MODULE_PARM_DESC(mali_debug_level, "Higher number, more dmesg output");
/* By default the module uses any available major, but it's possible to set it at load time to a specific number */
int mali_major = 0;
module_param(mali_major, int, S_IRUGO); /* r--r--r-- */
MODULE_PARM_DESC(mali_major, "Device major number");
int mali_benchmark = 0;
module_param(mali_benchmark, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
MODULE_PARM_DESC(mali_benchmark, "Bypass Mali hardware when non-zero");
extern int mali_hang_check_interval;
module_param(mali_hang_check_interval, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(mali_hang_check_interval, "Interval at which to check for progress after the hw watchdog has been triggered");
extern int mali_max_job_runtime;
module_param(mali_max_job_runtime, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(mali_max_job_runtime, "Maximum allowed job runtime in msecs.\nJobs will be killed after this no matter what");
#if defined(USING_MALI400_L2_CACHE)
extern int mali_l2_max_reads;
module_param(mali_l2_max_reads, int, S_IRUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(mali_l2_max_reads, "Maximum reads for Mali L2 cache");
#endif
static char mali_dev_name[] = "mali"; /* should be const, but the functions we call requires non-cost */
/* the mali device */
static struct mali_dev device;
/* uncached remapped memory, for an STBus uncached write barrier */
struct page *stbus_barrier_system_page;
volatile int *stbus_system_memory_barrier;
/*
* probed platform device pointer, note this is not static as we need access
* to it in the resource code.
*/
struct platform_device *mali_platform_device;
static int mali_open(struct inode *inode, struct file *filp);
static int mali_release(struct inode *inode, struct file *filp);
#ifdef HAVE_UNLOCKED_IOCTL
static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
#else
static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
#endif
static int mali_mmap(struct file * filp, struct vm_area_struct * vma);
/* Linux char file operations provided by the Mali module */
struct file_operations mali_fops =
{
.owner = THIS_MODULE,
.open = mali_open,
.release = mali_release,
#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = mali_ioctl,
#else
.ioctl = mali_ioctl,
#endif
.mmap = mali_mmap
};
int mali_driver_init(void)
{
int err;
u32 phys;
stbus_barrier_system_page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN, 1 );
if(NULL == stbus_barrier_system_page)
return -ENOMEM;
#if defined(__sh__)
SetPageReserved(stbus_barrier_system_page);
#endif
phys = page_to_phys( stbus_barrier_system_page );
stbus_system_memory_barrier = (int *)ioremap_nocache(phys,sizeof(int));
if(NULL == stbus_system_memory_barrier)
{
__free_pages(stbus_barrier_system_page,1);
return -ENOMEM;
}
*stbus_system_memory_barrier = 0;
#if USING_MALI_PMM
#if MALI_LICENSE_IS_GPL
err = _mali_dev_platform_register();
if (err)
{
__free_pages(stbus_barrier_system_page,1);
return err;
}
#endif
#endif
err = mali_kernel_constructor();
if (_MALI_OSK_ERR_OK != err)
{
MALI_PRINT(("Failed to initialize driver (error %d)\n", err));
return -EFAULT;
}
return 0;
}
void mali_driver_exit(void)
{
#if USING_MALI_PMM
malipmm_force_powerup();
#endif
mali_kernel_destructor();
if(NULL != stbus_system_memory_barrier)
iounmap((void*)stbus_system_memory_barrier);
if(NULL != stbus_barrier_system_page)
{
#if defined(__sh__)
ClearPageReserved(stbus_barrier_system_page);
#endif
__free_pages(stbus_barrier_system_page,1);
}
#if USING_MALI_PMM
malipmm_force_powerdown();
#endif
#if USING_MALI_PMM
#if MALI_LICENSE_IS_GPL
_mali_dev_platform_unregister();
#endif
#endif
}
/* called from _mali_osk_init */
int initialize_kernel_device(void)
{
int err;
dev_t dev = 0;
if (0 == mali_major)
{
/* auto select a major */
err = alloc_chrdev_region(&dev, 0/*first minor*/, 1/*count*/, mali_dev_name);
mali_major = MAJOR(dev);
}
else
{
/* use load time defined major number */
dev = MKDEV(mali_major, 0);
err = register_chrdev_region(dev, 1/*count*/, mali_dev_name);
}
if (err)
{
goto init_chrdev_err;
}
memset(&device, 0, sizeof(device));
/* initialize our char dev data */
cdev_init(&device.cdev, &mali_fops);
device.cdev.owner = THIS_MODULE;
device.cdev.ops = &mali_fops;
kobject_set_name(&(device.cdev.kobj), mali_dev_name);
/* register char dev with the kernel */
err = cdev_add(&device.cdev, dev, 1/*count*/);
if (err)
{
goto init_cdev_err;
}
err = mali_sysfs_register(&device, dev, mali_dev_name);
if (err)
{
goto init_sysfs_err;
}
/* Success! */
return 0;
init_sysfs_err:
cdev_del(&device.cdev);
init_cdev_err:
unregister_chrdev_region(dev, 1/*count*/);
init_chrdev_err:
return err;
}
/* called from _mali_osk_term */
void terminate_kernel_device(void)
{
dev_t dev = MKDEV(mali_major, 0);
mali_sysfs_unregister(&device, dev, mali_dev_name);
/* unregister char device */
cdev_del(&device.cdev);
/* free major */
unregister_chrdev_region(dev, 1/*count*/);
return;
}
/** @note munmap handler is done by vma close handler */
static int mali_mmap(struct file * filp, struct vm_area_struct * vma)
{
struct mali_session_data * session_data;
_mali_uk_mem_mmap_s args = {0, };
session_data = (struct mali_session_data *)filp->private_data;
if (NULL == session_data)
{
MALI_PRINT_ERROR(("mmap called without any session data available\n"));
return -EFAULT;
}
MALI_DEBUG_PRINT(3, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X\n", (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT), (unsigned int)(vma->vm_end - vma->vm_start)) );
/* Re-pack the arguments that mmap() packed for us */
args.ctx = session_data;
args.phys_addr = vma->vm_pgoff << PAGE_SHIFT;
args.size = vma->vm_end - vma->vm_start;
args.ukk_private = vma;
/* Call the common mmap handler */
MALI_CHECK(_MALI_OSK_ERR_OK ==_mali_ukk_mem_mmap( &args ), -EFAULT);
return 0;
}
static int mali_open(struct inode *inode, struct file *filp)
{
struct mali_session_data * session_data;
_mali_osk_errcode_t err;
/* input validation */
if (0 != MINOR(inode->i_rdev)) return -ENODEV;
/* allocated struct to track this session */
err = _mali_ukk_open((void **)&session_data);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
/* initialize file pointer */
filp->f_pos = 0;
/* link in our session data */
filp->private_data = (void*)session_data;
return 0;
}
static int mali_release(struct inode *inode, struct file *filp)
{
_mali_osk_errcode_t err;
/* input validation */
if (0 != MINOR(inode->i_rdev)) return -ENODEV;
err = _mali_ukk_close((void **)&filp->private_data);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
return 0;
}
int map_errcode( _mali_osk_errcode_t err )
{
switch(err)
{
case _MALI_OSK_ERR_OK : return 0;
case _MALI_OSK_ERR_FAULT: return -EFAULT;
case _MALI_OSK_ERR_INVALID_FUNC: return -ENOTTY;
case _MALI_OSK_ERR_INVALID_ARGS: return -EINVAL;
case _MALI_OSK_ERR_NOMEM: return -ENOMEM;
case _MALI_OSK_ERR_TIMEOUT: return -ETIMEDOUT;
case _MALI_OSK_ERR_RESTARTSYSCALL: return -ERESTARTSYS;
case _MALI_OSK_ERR_ITEM_NOT_FOUND: return -ENOENT;
default: return -EFAULT;
}
}
#ifdef HAVE_UNLOCKED_IOCTL
static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
int err;
struct mali_session_data *session_data;
#ifndef HAVE_UNLOCKED_IOCTL
/* inode not used */
(void)inode;
#endif
MALI_DEBUG_PRINT(7, ("Ioctl received 0x%08X 0x%08lX\n", cmd, arg));
session_data = (struct mali_session_data *)filp->private_data;
if (NULL == session_data)
{
MALI_DEBUG_PRINT(7, ("filp->private_data was NULL\n"));
return -ENOTTY;
}
if (NULL == (void *)arg)
{
MALI_DEBUG_PRINT(7, ("arg was NULL\n"));
return -ENOTTY;
}
switch(cmd)
{
case MALI_IOC_GET_SYSTEM_INFO_SIZE:
err = get_system_info_size_wrapper(session_data, (_mali_uk_get_system_info_size_s __user *)arg);
break;
case MALI_IOC_GET_SYSTEM_INFO:
err = get_system_info_wrapper(session_data, (_mali_uk_get_system_info_s __user *)arg);
break;
case MALI_IOC_WAIT_FOR_NOTIFICATION:
err = wait_for_notification_wrapper(session_data, (_mali_uk_wait_for_notification_s __user *)arg);
break;
case MALI_IOC_GET_API_VERSION:
err = get_api_version_wrapper(session_data, (_mali_uk_get_api_version_s __user *)arg);
break;
case MALI_IOC_POST_NOTIFICATION:
err = post_notification_wrapper(session_data, (_mali_uk_post_notification_s __user *)arg);
break;
#if MALI_TIMELINE_PROFILING_ENABLED
case MALI_IOC_PROFILING_START:
err = profiling_start_wrapper(session_data, (_mali_uk_profiling_start_s __user *)arg);
break;
case MALI_IOC_PROFILING_ADD_EVENT:
err = profiling_add_event_wrapper(session_data, (_mali_uk_profiling_add_event_s __user *)arg);
break;
case MALI_IOC_PROFILING_STOP:
err = profiling_stop_wrapper(session_data, (_mali_uk_profiling_stop_s __user *)arg);
break;
case MALI_IOC_PROFILING_GET_EVENT:
err = profiling_get_event_wrapper(session_data, (_mali_uk_profiling_get_event_s __user *)arg);
break;
case MALI_IOC_PROFILING_CLEAR:
err = profiling_clear_wrapper(session_data, (_mali_uk_profiling_clear_s __user *)arg);
break;
#endif
case MALI_IOC_MEM_INIT:
err = mem_init_wrapper(session_data, (_mali_uk_init_mem_s __user *)arg);
break;
case MALI_IOC_MEM_TERM:
err = mem_term_wrapper(session_data, (_mali_uk_term_mem_s __user *)arg);
break;
case MALI_IOC_MEM_MAP_EXT:
err = mem_map_ext_wrapper(session_data, (_mali_uk_map_external_mem_s __user *)arg);
break;
case MALI_IOC_MEM_UNMAP_EXT:
err = mem_unmap_ext_wrapper(session_data, (_mali_uk_unmap_external_mem_s __user *)arg);
break;
case MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE:
err = mem_query_mmu_page_table_dump_size_wrapper(session_data, (_mali_uk_query_mmu_page_table_dump_size_s __user *)arg);
break;
case MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE:
err = mem_dump_mmu_page_table_wrapper(session_data, (_mali_uk_dump_mmu_page_table_s __user *)arg);
break;
case MALI_IOC_MEM_GET_BIG_BLOCK:
err = mem_get_big_block_wrapper(filp, (_mali_uk_get_big_block_s __user *)arg);
break;
case MALI_IOC_MEM_FREE_BIG_BLOCK:
err = mem_free_big_block_wrapper(session_data, (_mali_uk_free_big_block_s __user *)arg);
break;
#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0
case MALI_IOC_MEM_ATTACH_UMP:
err = mem_attach_ump_wrapper(session_data, (_mali_uk_attach_ump_mem_s __user *)arg);
break;
case MALI_IOC_MEM_RELEASE_UMP:
err = mem_release_ump_wrapper(session_data, (_mali_uk_release_ump_mem_s __user *)arg);
break;
#else
case MALI_IOC_MEM_ATTACH_UMP:
case MALI_IOC_MEM_RELEASE_UMP: /* FALL-THROUGH */
MALI_DEBUG_PRINT(2, ("UMP not supported\n"));
err = -ENOTTY;
break;
#endif
case MALI_IOC_PP_START_JOB:
err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg);
break;
case MALI_IOC_PP_ABORT_JOB:
err = pp_abort_job_wrapper(session_data, (_mali_uk_pp_abort_job_s __user *)arg);
break;
case MALI_IOC_PP_NUMBER_OF_CORES_GET:
err = pp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_pp_number_of_cores_s __user *)arg);
break;
case MALI_IOC_PP_CORE_VERSION_GET:
err = pp_get_core_version_wrapper(session_data, (_mali_uk_get_pp_core_version_s __user *)arg);
break;
case MALI_IOC_GP2_START_JOB:
err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg);
break;
case MALI_IOC_GP2_ABORT_JOB:
err = gp_abort_job_wrapper(session_data, (_mali_uk_gp_abort_job_s __user *)arg);
break;
case MALI_IOC_GP2_NUMBER_OF_CORES_GET:
err = gp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_gp_number_of_cores_s __user *)arg);
break;
case MALI_IOC_GP2_CORE_VERSION_GET:
err = gp_get_core_version_wrapper(session_data, (_mali_uk_get_gp_core_version_s __user *)arg);
break;
case MALI_IOC_GP2_SUSPEND_RESPONSE:
err = gp_suspend_response_wrapper(session_data, (_mali_uk_gp_suspend_response_s __user *)arg);
break;
case MALI_IOC_VSYNC_EVENT_REPORT:
err = vsync_event_report_wrapper(session_data, (_mali_uk_vsync_event_report_s __user *)arg);
break;
default:
MALI_DEBUG_PRINT(2, ("No handler for ioctl 0x%08X 0x%08lX\n", cmd, arg));
err = -ENOTTY;
};
return err;
}
module_init(mali_driver_init);
module_exit(mali_driver_exit);
MODULE_LICENSE(MALI_KERNEL_LINUX_LICENSE);
MODULE_AUTHOR("ARM Ltd.");
MODULE_VERSION(SVN_REV_STRING);

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_LINUX_H__
#define __MALI_KERNEL_LINUX_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <linux/cdev.h> /* character device definitions */
#include "mali_kernel_license.h"
struct mali_dev
{
struct cdev cdev;
#if MALI_LICENSE_IS_GPL
struct class * mali_class;
#endif
};
_mali_osk_errcode_t initialize_kernel_device(void);
void terminate_kernel_device(void);
void mali_osk_low_level_mem_init(void);
void mali_osk_low_level_mem_term(void);
#ifdef __cplusplus
}
#endif
#endif /* __MALI_KERNEL_LINUX_H__ */

View File

@@ -0,0 +1,801 @@
/**
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
* Copyright (C) 2011 STMicroelectronics R&D Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* Even if the knl has no PM we need to configure it here so we have access to ARM's
* platform driver code implementation. */
#ifndef CONFIG_PM
#define CONFIG_PM
#endif
/**
* @file mali_kernel_pm.c
* Implementation of the Linux Power Management for Mali GPU kernel driver
*/
#if USING_MALI_PMM
#include <linux/sched.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif /* CONFIG_HAS_EARLYSUSPEND */
#ifdef CONFIG_PM_RUNTIME
#include <linux/pm_runtime.h>
#endif /* CONFIG_PM_RUNTIME */
#include <linux/platform_device.h>
#include <linux/version.h>
#include <asm/current.h>
#include <asm/delay.h>
#include <linux/suspend.h>
#include "mali_platform.h"
#include "mali_osk.h"
#include "mali_uk_types.h"
#include "mali_pmm.h"
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_license.h"
#include "mali_kernel_pm.h"
#include "mali_device_pause_resume.h"
#include "mali_linux_pm.h"
#if MALI_GPU_UTILIZATION
#include "mali_kernel_utilization.h"
#endif /* MALI_GPU_UTILIZATION */
#if MALI_POWER_MGMT_TEST_SUITE
#ifdef CONFIG_PM
#include "mali_linux_pm_testsuite.h"
unsigned int pwr_mgmt_status_reg = 0;
#endif /* CONFIG_PM */
#endif /* MALI_POWER_MGMT_TEST_SUITE */
#if MALI_STATE_TRACKING
int is_os_pmm_thread_waiting = -1;
#endif /* MALI_STATE_TRACKING */
extern struct platform_device *mali_platform_device;
/* kernel should be configured with power management support */
#ifdef CONFIG_PM
/* License should be GPL */
#if MALI_LICENSE_IS_GPL
/* Linux kernel major version */
#define LINUX_KERNEL_MAJOR_VERSION 2
/* Linux kernel minor version */
#define LINUX_KERNEL_MINOR_VERSION 6
/* Linux kernel development version */
#define LINUX_KERNEL_DEVELOPMENT_VERSION 29
#ifdef CONFIG_PM_DEBUG
static const char* const mali_states[_MALI_MAX_DEBUG_OPERATIONS] = {
[_MALI_DEVICE_SUSPEND] = "suspend",
[_MALI_DEVICE_RESUME] = "resume",
#ifdef CONFIG_HAS_EARLYSUSPEND
[_MALI_DEVICE_EARLYSUSPEND_DISABLE_FB] = "early_suspend_level_disable_framebuffer",
[_MALI_DEVICE_LATERESUME] = "late_resume",
#endif /* CONFIG_HAS_EARLYSUSPEND */
[_MALI_DVFS_PAUSE_EVENT] = "dvfs_pause",
[_MALI_DVFS_RESUME_EVENT] = "dvfs_resume",
};
#endif /* CONFIG_PM_DEBUG */
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
extern void set_mali_parent_power_domain(struct platform_device* dev);
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
#ifndef CONFIG_HAS_EARLYSUSPEND
static int mali_pwr_suspend_notifier(struct notifier_block *nb,unsigned long event,void* dummy);
static struct notifier_block mali_pwr_notif_block = {
.notifier_call = mali_pwr_suspend_notifier
};
#endif /* CONFIG_HAS_EARLYSUSPEND */
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
/* Power management thread pointer */
struct task_struct *pm_thread;
/* dvfs power management thread */
struct task_struct *dvfs_pm_thread;
/* is wake up needed */
short is_wake_up_needed = 0;
int timeout_fired = 2;
unsigned int is_mali_pmm_testsuite_enabled = 0;
_mali_device_power_states mali_device_state = _MALI_DEVICE_RESUME;
_mali_device_power_states mali_dvfs_device_state = _MALI_DEVICE_RESUME;
_mali_osk_lock_t *lock;
#if MALI_POWER_MGMT_TEST_SUITE
const char* const mali_pmm_recording_events[_MALI_DEVICE_MAX_PMM_EVENTS] = {
[_MALI_DEVICE_PMM_TIMEOUT_EVENT] = "timeout",
[_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS] = "job_scheduling",
[_MALI_DEVICE_PMM_REGISTERED_CORES] = "cores",
};
unsigned int mali_timeout_event_recording_on = 0;
unsigned int mali_job_scheduling_events_recording_on = 0;
unsigned int is_mali_pmu_present = 0;
#endif /* MALI_POWER_MGMT_TEST_SUITE */
/* Function prototypes */
static int mali_pm_probe(struct platform_device *pdev);
static int mali_pm_remove(struct platform_device *pdev);
/* Mali device suspend function */
static int mali_pm_suspend(struct device *dev);
/* Mali device resume function */
static int mali_pm_resume(struct device *dev);
/* Run time suspend and resume functions */
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
static int mali_device_runtime_suspend(struct device *dev);
static int mali_device_runtime_resume(struct device *dev);
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
/* Early suspend functions */
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mali_pm_early_suspend(struct early_suspend *mali_dev);
static void mali_pm_late_resume(struct early_suspend *mali_dev);
#endif /* CONFIG_HAS_EARLYSUSPEND */
/* OS suspend and resume callbacks */
#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON
#ifndef CONFIG_PM_RUNTIME
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
static int mali_pm_os_suspend(struct platform_device *pdev, pm_message_t state);
#else
static int mali_pm_os_suspend(struct device *dev);
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
static int mali_pm_os_resume(struct platform_device *pdev);
#else
static int mali_pm_os_resume(struct device *dev);
#endif
#endif /* CONFIG_PM_RUNTIME */
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
/* OS Hibernation suspend callback */
static int mali_pm_os_suspend_on_hibernation(struct device *dev);
/* OS Hibernation resume callback */
static int mali_pm_os_resume_on_hibernation(struct device *dev);
static void _mali_release_pm(struct device* device);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
static const struct dev_pm_ops mali_dev_pm_ops = {
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
.runtime_suspend = mali_device_runtime_suspend,
.runtime_resume = mali_device_runtime_resume,
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
#ifndef CONFIG_PM_RUNTIME
#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON
.suspend = mali_pm_os_suspend,
.resume = mali_pm_os_resume,
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
.freeze = mali_pm_os_suspend_on_hibernation,
.poweroff = mali_pm_os_suspend_on_hibernation,
.thaw = mali_pm_os_resume_on_hibernation,
.restore = mali_pm_os_resume_on_hibernation,
};
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
struct pm_ext_ops mali_pm_operations = {
.base = {
.freeze = mali_pm_os_suspend_on_hibernation,
.thaw = mali_pm_os_resume_on_hibernation,
.poweroff = mali_pm_os_resume_on_hibernation,
.restore = mali_pm_os_resume_on_hibernation,
},
};
#endif
static struct platform_driver mali_plat_driver = {
.probe = mali_pm_probe,
.remove = mali_pm_remove,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
#ifndef CONFIG_PM_RUNTIME
#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON
.suspend = mali_pm_os_suspend,
.resume = mali_pm_os_resume,
#endif /* CONFIG_PM_RUNTIME */
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
.pm = &mali_pm_operations,
#endif
.driver = {
.name = "mali",
.owner = THIS_MODULE,
.bus = &platform_bus_type,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
.pm = &mali_dev_pm_ops,
#endif
},
};
#ifdef CONFIG_HAS_EARLYSUSPEND
/* Early suspend hooks */
static struct early_suspend mali_dev_early_suspend = {
.suspend = mali_pm_early_suspend,
.resume = mali_pm_late_resume,
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
};
#endif /* CONFIG_HAS_EARLYSUSPEND */
/* Mali GPU platform device */
struct platform_device mali_gpu_device = {
.name = "mali_dev",
.id = 0,
.dev.release = _mali_release_pm
};
/** This function is called when platform device is unregistered. This function
* is necessary when the platform device is unregistered.
*/
static void _mali_release_pm(struct device *device)
{
MALI_DEBUG_PRINT(4, ("OSPMM: MALI Platform device removed\n" ));
}
#if MALI_POWER_MGMT_TEST_SUITE
void mali_is_pmu_present(void)
{
int temp = 0;
temp = pmu_get_power_up_down_info();
if (4095 == temp)
{
is_mali_pmu_present = 0;
}
else
{
is_mali_pmu_present = 1;
}
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
#endif /* MALI_LICENSE_IS_GPL */
#if MALI_LICENSE_IS_GPL
static int mali_wait_for_power_management_policy_event(void)
{
int err = 0;
for (; ;)
{
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current))
{
err = -EINTR;
break;
}
if (is_wake_up_needed == 1)
{
break;
}
schedule();
}
__set_current_state(TASK_RUNNING);
is_wake_up_needed =0;
return err;
}
/** This function is invoked when mali device is suspended
*/
int mali_device_suspend(unsigned int event_id, struct task_struct **pwr_mgmt_thread)
{
int err = 0;
_mali_uk_pmm_message_s event = {
NULL,
event_id,
timeout_fired};
*pwr_mgmt_thread = current;
MALI_DEBUG_PRINT(4, ("OSPMM: MALI device is being suspended\n" ));
_mali_ukk_pmm_event_message(&event);
#if MALI_STATE_TRACKING
is_os_pmm_thread_waiting = 1;
#endif /* MALI_STATE_TRACKING */
err = mali_wait_for_power_management_policy_event();
#if MALI_STATE_TRACKING
is_os_pmm_thread_waiting = 0;
#endif /* MALI_STATE_TRACKING */
return err;
}
/** This function is called when Operating system wants to power down
* the mali GPU device.
*/
static int mali_pm_suspend(struct device *dev)
{
int err = 0;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
#if MALI_GPU_UTILIZATION
mali_utilization_suspend();
#endif /* MALI_GPU_UTILIZATION */
if ((mali_device_state == _MALI_DEVICE_SUSPEND)
#ifdef CONFIG_HAS_EARLYSUSPEND
|| mali_device_state == (_MALI_DEVICE_EARLYSUSPEND_DISABLE_FB))
#else
)
#endif /* CONFIG_HAS_EARLYSUSPEND */
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
mali_device_state = _MALI_DEVICE_SUSPEND_IN_PROGRESS;
err = mali_device_suspend(MALI_PMM_EVENT_OS_POWER_DOWN, &pm_thread);
mali_device_state = _MALI_DEVICE_SUSPEND;
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
#ifndef CONFIG_PM_RUNTIME
#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
static int mali_pm_os_suspend(struct platform_device *pdev, pm_message_t state)
#else
static int mali_pm_os_suspend(struct device *dev)
#endif
{
int err = 0;
err = mali_pm_suspend(NULL);
return err;
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
#ifndef CONFIG_HAS_EARLYSUSPEND
static int mali_pwr_suspend_notifier(struct notifier_block *nb,unsigned long event,void* dummy)
{
int err = 0;
switch (event)
{
case PM_SUSPEND_PREPARE:
err = mali_pm_suspend(NULL);
break;
case PM_POST_SUSPEND:
err = mali_pm_resume(NULL);
break;
default:
break;
}
return 0;
}
#endif /* CONFIG_HAS_EARLYSUSPEND */
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
/** This function is called when mali GPU device is to be resumed.
*/
int mali_device_resume(unsigned int event_id, struct task_struct **pwr_mgmt_thread)
{
int err = 0;
_mali_uk_pmm_message_s event = {
NULL,
event_id,
timeout_fired};
*pwr_mgmt_thread = current;
MALI_DEBUG_PRINT(4, ("OSPMM: MALI device is being resumed\n" ));
_mali_ukk_pmm_event_message(&event);
MALI_DEBUG_PRINT(4, ("OSPMM: MALI Power up event is scheduled\n" ));
#if MALI_STATE_TRACKING
is_os_pmm_thread_waiting = 1;
#endif /* MALI_STATE_TRACKING */
err = mali_wait_for_power_management_policy_event();
#if MALI_STATE_TRACKING
is_os_pmm_thread_waiting = 0;
#endif /* MALI_STATE_TRACKING */
return err;
}
/** This function is called when mali GPU device is to be resumed
*/
static int mali_pm_resume(struct device *dev)
{
int err = 0;
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (mali_device_state == _MALI_DEVICE_RESUME)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
err = mali_device_resume(MALI_PMM_EVENT_OS_POWER_UP, &pm_thread);
mali_device_state = _MALI_DEVICE_RESUME;
mali_dvfs_device_state = _MALI_DEVICE_RESUME;
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return err;
}
#ifndef CONFIG_PM_RUNTIME
#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON
#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION))
static int mali_pm_os_resume(struct platform_device *pdev)
#else
static int mali_pm_os_resume(struct device *dev)
#endif
{
int err = 0;
err = mali_pm_resume(NULL);
return err;
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
static int mali_pm_os_suspend_on_hibernation(struct device *dev)
{
int err = 0;
err = mali_pm_suspend(NULL);
return err;
}
static int mali_pm_os_resume_on_hibernation(struct device *dev)
{
int err = 0;
err = mali_pm_resume(NULL);
return err;
}
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
/** This function is called when runtime suspend of mali device is required.
*/
static int mali_device_runtime_suspend(struct device *dev)
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time suspended \n" ));
return 0;
}
/** This function is called when runtime resume of mali device is required.
*/
static int mali_device_runtime_resume(struct device *dev)
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time Resumed \n" ));
return 0;
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_HAS_EARLYSUSPEND
/* This function is called from android framework.
*/
static void mali_pm_early_suspend(struct early_suspend *mali_dev)
{
switch(mali_dev->level)
{
/* Screen should be turned off but framebuffer will be accessible */
case EARLY_SUSPEND_LEVEL_BLANK_SCREEN:
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Screen is off\n" ));
break;
case EARLY_SUSPEND_LEVEL_STOP_DRAWING:
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Suspend level stop drawing\n" ));
break;
/* Turn off the framebuffer. In our case No Mali GPU operation */
case EARLY_SUSPEND_LEVEL_DISABLE_FB:
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Suspend level Disable framebuffer\n" ));
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
#if MALI_GPU_UTILIZATION
mali_utilization_suspend();
#endif /* MALI_GPU_UTILIZATION */
if ((mali_device_state == _MALI_DEVICE_SUSPEND) || (mali_device_state == _MALI_DEVICE_EARLYSUSPEND_DISABLE_FB))
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return;
}
mali_device_suspend(MALI_PMM_EVENT_OS_POWER_DOWN, &pm_thread);
mali_device_state = _MALI_DEVICE_EARLYSUSPEND_DISABLE_FB;
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
break;
default:
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Invalid Suspend Mode\n" ));
break;
}
}
/* This function is invoked from android framework when mali device needs to be
* resumed.
*/
static void mali_pm_late_resume(struct early_suspend *mali_dev)
{
_mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
if (mali_device_state == _MALI_DEVICE_RESUME)
{
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
return;
}
if (mali_device_state == _MALI_DEVICE_EARLYSUSPEND_DISABLE_FB)
{
mali_device_resume(MALI_PMM_EVENT_OS_POWER_UP, &pm_thread);
mali_dvfs_device_state = _MALI_DEVICE_RESUME;
mali_device_state = _MALI_DEVICE_RESUME;
}
_mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
}
#endif /* CONFIG_HAS_EARLYSUSPEND */
#ifdef CONFIG_PM_DEBUG
/** This function is used for debugging purposes when the user want to see
* which power management operations are supported for
* mali device.
*/
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
{
char *str = buf;
#if !MALI_POWER_MGMT_TEST_SUITE
int pm_counter = 0;
for (pm_counter = 0; pm_counter<_MALI_MAX_DEBUG_OPERATIONS; pm_counter++)
{
str += sprintf(str, "%s ", mali_states[pm_counter]);
}
#else
str += sprintf(str, "%d ",pwr_mgmt_status_reg);
#endif
if (str != buf)
{
*(str-1) = '\n';
}
return (str-buf);
}
/** This function is called when user wants to suspend the mali GPU device in order
* to simulate the power up and power down events.
*/
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int err = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend mali_dev;
#endif /* CONFIG_HAS_EARLYSUSPEND */
#if MALI_POWER_MGMT_TEST_SUITE
int test_flag_dvfs = 0;
pwr_mgmt_status_reg = 0;
mali_is_pmu_present();
#endif
if (!strncmp(buf,mali_states[_MALI_DEVICE_SUSPEND],strlen(mali_states[_MALI_DEVICE_SUSPEND])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI suspend Power operation is scheduled\n" ));
err = mali_pm_suspend(NULL);
}
#if MALI_POWER_MGMT_TEST_SUITE
else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_REGISTERED_CORES],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_REGISTERED_CORES])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Device get number of registerd cores\n" ));
pwr_mgmt_status_reg = _mali_pmm_cores_list();
return count;
}
else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_TIMEOUT_EVENT],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_TIMEOUT_EVENT])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI timeout event recording is enabled\n" ));
mali_timeout_event_recording_on = 1;
}
else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Job scheduling events recording is enabled\n" ));
mali_job_scheduling_events_recording_on = 1;
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
else if (!strncmp(buf,mali_states[_MALI_DEVICE_RESUME],strlen(mali_states[_MALI_DEVICE_RESUME])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Resume Power operation is scheduled\n" ));
err = mali_pm_resume(NULL);
}
#ifdef CONFIG_HAS_EARLYSUSPEND
else if (!strncmp(buf,mali_states[_MALI_DEVICE_EARLYSUSPEND_DISABLE_FB],strlen(mali_states[_MALI_DEVICE_EARLYSUSPEND_DISABLE_FB])))
{
mali_dev.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Android early suspend operation is scheduled\n" ));
mali_pm_early_suspend(&mali_dev);
}
else if (!strncmp(buf,mali_states[_MALI_DEVICE_LATERESUME],strlen(mali_states[_MALI_DEVICE_LATERESUME])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Resume Power operation is scheduled\n" ));
mali_pm_late_resume(NULL);
}
#endif /* CONFIG_HAS_EARLYSUSPEND */
else if (!strncmp(buf,mali_states[_MALI_DVFS_PAUSE_EVENT],strlen(mali_states[_MALI_DVFS_PAUSE_EVENT])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI DVFS Pause Power operation is scheduled\n" ));
err = mali_dev_pause();
#if MALI_POWER_MGMT_TEST_SUITE
test_flag_dvfs = 1;
#endif /* MALI_POWER_MGMT_TEST_SUITE */
}
else if (!strncmp(buf,mali_states[_MALI_DVFS_RESUME_EVENT],strlen(mali_states[_MALI_DVFS_RESUME_EVENT])))
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI DVFS Resume Power operation is scheduled\n" ));
err = mali_dev_resume();
#if MALI_POWER_MGMT_TEST_SUITE
test_flag_dvfs = 1;
#endif /* MALI_POWER_MGMT_TEST_SUITE */
}
else
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Invalid Power Mode Operation selected\n" ));
}
#if MALI_POWER_MGMT_TEST_SUITE
if (test_flag_dvfs == 1)
{
if (err)
{
pwr_mgmt_status_reg = 2;
}
else
{
pwr_mgmt_status_reg = 1;
}
}
else
{
if (1 == is_mali_pmu_present)
{
pwr_mgmt_status_reg = pmu_get_power_up_down_info();
}
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
return count;
}
/* Device attribute file */
static DEVICE_ATTR(file, 0644, show_file, store_file);
#endif /* CONFIG_PM_DEBUG */
static int mali_pm_remove(struct platform_device *pdev)
{
#ifdef CONFIG_PM_DEBUG
device_remove_file(&mali_gpu_device.dev, &dev_attr_file);
#endif /* CONFIG_PM_DEBUG */
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
pm_runtime_disable(&pdev->dev);
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
return 0;
}
/** This function is called when the device is probed */
static int mali_pm_probe(struct platform_device *pdev)
{
MALI_DEBUG_PRINT(2, ("Mali Platform device probe id = %d num_resources = %d resource = %p.\n",pdev->id,pdev->num_resources,pdev->resource));
/*
* As OS init has already created the platform device we record it in the global
*/
mali_platform_device = pdev;
#ifdef CONFIG_PM_DEBUG
int err;
err = device_create_file(&mali_gpu_device.dev, &dev_attr_file);
if (err)
{
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Error in creating device file\n" ));
}
#endif /* CONFIG_PM_DEBUG */
return 0;
}
/** This function is called when Mali GPU device is initialized
*/
int _mali_dev_platform_register(void)
{
int err;
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
set_mali_parent_power_domain(&mali_gpu_device);
#endif
#ifdef CONFIG_PM_RUNTIME
#ifndef CONFIG_HAS_EARLYSUSPEND
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
err = register_pm_notifier(&mali_pwr_notif_block);
if (err)
{
return err;
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_HAS_EARLYSUSPEND */
#endif /* CONFIG_PM_RUNTIME */
/* The platform device is actually registered by the OS startup code so we don't
* need to do it here. All we do is register the platform driver
*/
MALI_DEBUG_PRINT(3, ("[%s] Not registering platform device\n", __FUNCTION__));
lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)( _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 0);
err = platform_driver_register(&mali_plat_driver);
if (!err)
{
#ifdef CONFIG_HAS_EARLYSUSPEND
register_early_suspend(&mali_dev_early_suspend);
#endif /* CONFIG_HAS_EARLYSUSPEND */
}
else
{
_mali_osk_lock_term(lock);
#ifdef CONFIG_PM_RUNTIME
#ifndef CONFIG_HAS_EARLYSUSPEND
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
unregister_pm_notifier(&mali_pwr_notif_block);
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_HAS_EARLYSUSPEND */
#endif /* CONFIG_PM_RUNTIME */
}
return err;
}
/** This function is called when Mali GPU device is unloaded
*/
void _mali_dev_platform_unregister(void)
{
_mali_osk_lock_term(lock);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&mali_dev_early_suspend);
#endif /* CONFIG_HAS_EARLYSUSPEND */
#ifdef CONFIG_PM_RUNTIME
#ifndef CONFIG_HAS_EARLYSUSPEND
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
unregister_pm_notifier(&mali_pwr_notif_block);
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_HAS_EARLYSUSPEND */
#endif /* CONFIG_PM_RUNTIME */
platform_driver_unregister(&mali_plat_driver);
/* We dont unregister the platform_device as it was registered by the OS not us */
}
#endif /* MALI_LICENSE_IS_GPL */
#endif /* CONFIG_PM */
#if MALI_STATE_TRACKING
u32 mali_pmm_dump_os_thread_state( char *buf, u32 size )
{
return snprintf(buf, size, "OSPMM: OS PMM thread is waiting: %s\n", is_os_pmm_thread_waiting ? "true" : "false");
}
#endif /* MALI_STATE_TRACKING */
#endif /* USING_MALI_PMM */

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_KERNEL_PM_H__
#define __MALI_KERNEL_PM_H__
#ifdef USING_MALI_PMM
int _mali_dev_platform_register(void);
void _mali_dev_platform_unregister(void);
#endif /* USING_MALI_PMM */
#endif /* __MALI_KERNEL_PM_H__ */

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_LINUX_PM_H__
#define __MALI_LINUX_PM_H__
#if USING_MALI_PMM
#ifdef CONFIG_PM
/* Number of power states supported for making power up and down */
typedef enum
{
_MALI_DEVICE_SUSPEND, /* Suspend */
_MALI_DEVICE_RESUME, /* Resume */
#ifdef CONFIG_HAS_EARLYSUSPEND
_MALI_DEVICE_EARLYSUSPEND_DISABLE_FB, /* Early suspend */
_MALI_DEVICE_LATERESUME, /* Late resume */
#endif /* CONFIG_HAS_EARLYSUSPEND */
_MALI_DEVICE_SUSPEND_IN_PROGRESS, /* Suspend in progress */
_MALI_DEVICE_MAX_POWER_STATES, /* Maximum power states */
} _mali_device_power_states;
/* Number of DVFS events */
typedef enum
{
_MALI_DVFS_PAUSE_EVENT = _MALI_DEVICE_MAX_POWER_STATES-1, /* DVFS Pause event */
_MALI_DVFS_RESUME_EVENT, /* DVFS Resume event */
_MALI_MAX_DEBUG_OPERATIONS,
} _mali_device_dvfs_events;
extern _mali_device_power_states mali_device_state;
extern _mali_device_power_states mali_dvfs_device_state;
extern _mali_osk_lock_t *lock;
extern short is_wake_up_needed;
extern int timeout_fired;
extern struct platform_device mali_gpu_device;
/* dvfs pm thread */
extern struct task_struct *dvfs_pm_thread;
/* Power management thread */
extern struct task_struct *pm_thread;
int mali_device_suspend(u32 event_id, struct task_struct **pwr_mgmt_thread);
int mali_device_resume(u32 event_id, struct task_struct **pwr_mgmt_thread);
#endif /* CONFIG_PM */
#endif /* USING_MALI_PMM */
#endif /* __MALI_LINUX_PM_H___ */

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MALI_LINUX_PM_TESTSUITE_H__
#define __MALI_LINUX_PM_TESTSUITE_H__
#if USING_MALI_PMM
#if MALI_POWER_MGMT_TEST_SUITE
#ifdef CONFIG_PM
typedef enum
{
_MALI_DEVICE_PMM_TIMEOUT_EVENT,
_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS,
_MALI_DEVICE_PMM_REGISTERED_CORES,
_MALI_DEVICE_MAX_PMM_EVENTS
} _mali_device_pmm_recording_events;
extern unsigned int mali_timeout_event_recording_on;
extern unsigned int mali_job_scheduling_events_recording_on;
extern unsigned int pwr_mgmt_status_reg;
extern unsigned int is_mali_pmm_testsuite_enabled;
extern unsigned int is_mali_pmu_present;
#endif /* CONFIG_PM */
#endif /* MALI_POWER_MGMT_TEST_SUITE */
#endif /* USING_MALI_PMM */
#endif /* __MALI_LINUX_PM_TESTSUITE_H__ */

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_atomics.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include "mali_osk.h"
#include <asm/atomic.h>
#include "mali_kernel_common.h"
void _mali_osk_atomic_dec( _mali_osk_atomic_t *atom )
{
atomic_dec((atomic_t *)&atom->u.val);
}
u32 _mali_osk_atomic_dec_return( _mali_osk_atomic_t *atom )
{
return atomic_dec_return((atomic_t *)&atom->u.val);
}
void _mali_osk_atomic_inc( _mali_osk_atomic_t *atom )
{
atomic_inc((atomic_t *)&atom->u.val);
}
u32 _mali_osk_atomic_inc_return( _mali_osk_atomic_t *atom )
{
return atomic_inc_return((atomic_t *)&atom->u.val);
}
_mali_osk_errcode_t _mali_osk_atomic_init( _mali_osk_atomic_t *atom, u32 val )
{
MALI_CHECK_NON_NULL(atom, _MALI_OSK_ERR_INVALID_ARGS);
atomic_set((atomic_t *)&atom->u.val, val);
return _MALI_OSK_ERR_OK;
}
u32 _mali_osk_atomic_read( _mali_osk_atomic_t *atom )
{
return atomic_read((atomic_t *)&atom->u.val);
}
void _mali_osk_atomic_term( _mali_osk_atomic_t *atom )
{
MALI_IGNORE(atom);
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/atomic.h>
#include "mali_osk.h"
#include "mali_ukk.h"
#include "mali_kernel_common.h"
/**
* @file mali_osk_specific.c
* Implementation of per-OS Kernel level specifics
*/
_mali_osk_errcode_t _mali_osk_specific_indirect_mmap( _mali_uk_mem_mmap_s *args )
{
/* args->ctx ignored here; args->ukk_private required instead */
/* we need to lock the mmap semaphore before calling the do_mmap function */
down_write(&current->mm->mmap_sem);
args->mapping = (void __user *)do_mmap(
(struct file *)args->ukk_private,
0, /* start mapping from any address after NULL */
args->size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
args->phys_addr
);
/* and unlock it after the call */
up_write(&current->mm->mmap_sem);
/* No cookie required here */
args->cookie = 0;
/* uku_private meaningless, so zero */
args->uku_private = NULL;
if ( (NULL == args->mapping) || IS_ERR((void *)args->mapping) )
{
return _MALI_OSK_ERR_FAULT;
}
/* Success */
return _MALI_OSK_ERR_OK;
}
_mali_osk_errcode_t _mali_osk_specific_indirect_munmap( _mali_uk_mem_munmap_s *args )
{
/* args->ctx and args->cookie ignored here */
if ((NULL != current) && (NULL != current->mm))
{
/* remove mapping of mali memory from the process' view */
/* lock mmap semaphore before call */
/* lock mmap_sem before calling do_munmap */
down_write(&current->mm->mmap_sem);
do_munmap(
current->mm,
(unsigned long)args->mapping,
args->size
);
/* and unlock after call */
up_write(&current->mm->mmap_sem);
MALI_DEBUG_PRINT(5, ("unmapped\n"));
}
else
{
MALI_DEBUG_PRINT(2, ("Freeing of a big block while no user process attached, assuming crash cleanup in progress\n"));
}
return _MALI_OSK_ERR_OK; /* always succeeds */
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_specific.h
* Defines per-OS Kernel level specifics, such as unusual workarounds for
* certain OSs.
*/
#ifndef __MALI_OSK_INDIR_MMAP_H__
#define __MALI_OSK_INDIR_MMAP_H__
#include "mali_uk_types.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* Linux specific means for calling _mali_ukk_mem_mmap/munmap
*
* The presence of _MALI_OSK_SPECIFIC_INDIRECT_MMAP indicates that
* _mali_osk_specific_indirect_mmap and _mali_osk_specific_indirect_munmap
* should be used instead of _mali_ukk_mem_mmap/_mali_ukk_mem_munmap.
*
* The arguments are the same as _mali_ukk_mem_mmap/_mali_ukk_mem_munmap.
*
* In ALL operating system other than Linux, it is expected that common code
* should be able to call _mali_ukk_mem_mmap/_mali_ukk_mem_munmap directly.
* Such systems should NOT define _MALI_OSK_SPECIFIC_INDIRECT_MMAP.
*/
_mali_osk_errcode_t _mali_osk_specific_indirect_mmap( _mali_uk_mem_mmap_s *args );
_mali_osk_errcode_t _mali_osk_specific_indirect_munmap( _mali_uk_mem_munmap_s *args );
#ifdef __cplusplus
}
#endif
#endif /* __MALI_OSK_INDIR_MMAP_H__ */

View File

@@ -0,0 +1,239 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_irq.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include <linux/slab.h> /* For memory allocation */
#include <linux/workqueue.h>
#include "mali_osk.h"
#include "mali_kernel_core.h"
#include "mali_kernel_common.h"
#include "mali_kernel_license.h"
#include "linux/interrupt.h"
typedef struct _mali_osk_irq_t_struct
{
u32 irqnum;
void *data;
_mali_osk_irq_uhandler_t uhandler;
_mali_osk_irq_bhandler_t bhandler;
struct work_struct work_queue_irq_handle; /* Workqueue for the bottom half of the IRQ-handling. This job is activated when this core gets an IRQ.*/
} mali_osk_irq_object_t;
#if MALI_LICENSE_IS_GPL
static struct workqueue_struct *pmm_wq=NULL;
#endif
typedef void (*workqueue_func_t)(void *);
typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *);
static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ); /* , struct pt_regs *regs*/
#if defined(INIT_DELAYED_WORK)
static void irq_handler_bottom_half ( struct work_struct *work );
#else
static void irq_handler_bottom_half ( void * input );
#endif
/**
* Linux kernel version has marked SA_SHIRQ as deprecated, IRQF_SHARED should be used.
* This is to handle older kernels which haven't done this swap.
*/
#ifndef IRQF_SHARED
#define IRQF_SHARED SA_SHIRQ
#endif /* IRQF_SHARED */
_mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandler, _mali_osk_irq_bhandler_t bhandler, _mali_osk_irq_trigger_t trigger_func, _mali_osk_irq_ack_t ack_func, void *data, const char *description )
{
mali_osk_irq_object_t *irq_object;
irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL);
if (NULL == irq_object) return NULL;
/* workqueue API changed in 2.6.20, support both versions: */
#if defined(INIT_DELAYED_WORK)
/* New syntax: INIT_WORK( struct work_struct *work, void (*function)(struct work_struct *)) */
INIT_WORK( &irq_object->work_queue_irq_handle, irq_handler_bottom_half);
#else
/* Old syntax: INIT_WORK( struct work_struct *work, void (*function)(void *), void *data) */
INIT_WORK( &irq_object->work_queue_irq_handle, irq_handler_bottom_half, irq_object);
#endif /* defined(INIT_DELAYED_WORK) */
if (-1 == irqnum)
{
/* Probe for IRQ */
if ( (NULL != trigger_func) && (NULL != ack_func) )
{
unsigned long probe_count = 3;
_mali_osk_errcode_t err;
int irq;
MALI_DEBUG_PRINT(2, ("Probing for irq\n"));
do
{
unsigned long mask;
mask = probe_irq_on();
trigger_func(data);
_mali_osk_time_ubusydelay(5);
irq = probe_irq_off(mask);
err = ack_func(data);
}
while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--);
if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1;
else irqnum = irq;
}
else irqnum = -1; /* no probe functions, fault */
if (-1 != irqnum)
{
/* found an irq */
MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum));
}
else
{
MALI_DEBUG_PRINT(2, ("Probe for irq failed\n"));
}
}
irq_object->irqnum = irqnum;
irq_object->uhandler = uhandler;
irq_object->bhandler = bhandler;
irq_object->data = data;
/* Is this a real IRQ handler we need? */
if (!mali_benchmark && irqnum != _MALI_OSK_IRQ_NUMBER_FAKE && irqnum != _MALI_OSK_IRQ_NUMBER_PMM)
{
if (-1 == irqnum)
{
MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description));
kfree(irq_object);
return NULL;
}
if (0 != request_irq(irqnum, irq_handler_upper_half, IRQF_SHARED, description, irq_object))
{
MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description));
kfree(irq_object);
return NULL;
}
}
#if MALI_LICENSE_IS_GPL
if ( _MALI_OSK_IRQ_NUMBER_PMM == irqnum )
{
pmm_wq = create_singlethread_workqueue("mali-pmm-wq");
}
#endif
return irq_object;
}
void _mali_osk_irq_schedulework( _mali_osk_irq_t *irq )
{
mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
#if MALI_LICENSE_IS_GPL
if ( irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM )
{
queue_work( pmm_wq,&irq_object->work_queue_irq_handle );
}
else
{
#endif
schedule_work(&irq_object->work_queue_irq_handle);
#if MALI_LICENSE_IS_GPL
}
#endif
}
void _mali_osk_flush_workqueue( _mali_osk_irq_t *irq )
{
#if MALI_LICENSE_IS_GPL
mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
if(irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM )
{
flush_workqueue(pmm_wq);
}
#endif
}
void _mali_osk_irq_term( _mali_osk_irq_t *irq )
{
mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
#if MALI_LICENSE_IS_GPL
if(irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM )
{
flush_workqueue(pmm_wq);
destroy_workqueue(pmm_wq);
}
#endif
if (!mali_benchmark)
{
free_irq(irq_object->irqnum, irq_object);
}
kfree(irq_object);
flush_scheduled_work();
}
/** This function is called directly in interrupt context from the OS just after
* the CPU get the hw-irq from mali, or other devices on the same IRQ-channel.
* It is registered one of these function for each mali core. When an interrupt
* arrives this function will be called equal times as registered mali cores.
* That means that we only check one mali core in one function call, and the
* core we check for each turn is given by the \a dev_id variable.
* If we detect an pending interrupt on the given core, we mask the interrupt
* out by settging the core's IRQ_MASK register to zero.
* Then we schedule the mali_core_irq_handler_bottom_half to run as high priority
* work queue job.
*/
static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ) /* , struct pt_regs *regs*/
{
mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id;
if (irq_object->uhandler(irq_object->data) == _MALI_OSK_ERR_OK)
{
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/* Is executed when an interrupt occur on one core */
/* workqueue API changed in 2.6.20, support both versions: */
#if defined(INIT_DELAYED_WORK)
static void irq_handler_bottom_half ( struct work_struct *work )
#else
static void irq_handler_bottom_half ( void * input )
#endif
{
mali_osk_irq_object_t *irq_object;
#if defined(INIT_DELAYED_WORK)
irq_object = _MALI_OSK_CONTAINER_OF(work, mali_osk_irq_object_t, work_queue_irq_handle);
#else
if ( NULL == input )
{
MALI_PRINT_ERROR(("IRQ: Null pointer! Illegal!"));
return; /* Error */
}
irq_object = (mali_osk_irq_object_t *) input;
#endif
irq_object->bhandler(irq_object->data);
}

View File

@@ -0,0 +1,271 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_locks.c
* Implemenation of the OS abstraction layer for the kernel device driver
*/
/* needed to detect kernel version specific code */
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/rwsem.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <linux/semaphore.h>
#else /* pre 2.6.26 the file was in the arch specific location */
#include <asm/semaphore.h>
#endif
#include <linux/slab.h>
#include "mali_osk.h"
#include "mali_kernel_common.h"
/* These are all the locks we implement: */
typedef enum
{
_MALI_OSK_INTERNAL_LOCKTYPE_SPIN, /* Mutex, implicitly non-interruptable, use spin_lock/spin_unlock */
_MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ, /* Mutex, IRQ version of spinlock, use spin_lock_irqsave/spin_unlock_irqrestore */
_MALI_OSK_INTERNAL_LOCKTYPE_MUTEX, /* Interruptable, use up()/down_interruptable() */
_MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT, /* Non-Interruptable, use up()/down() */
_MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW, /* Non-interruptable, Reader/Writer, use {up,down}{read,write}() */
/* Linux supports, but we do not support:
* Non-Interruptable Reader/Writer spinlock mutexes - RW optimization will be switched off
*/
/* Linux does not support:
* One-locks, of any sort - no optimization for this fact will be made.
*/
} _mali_osk_internal_locktype;
struct _mali_osk_lock_t_struct
{
_mali_osk_internal_locktype type;
unsigned long flags;
union
{
spinlock_t spinlock;
struct semaphore sema;
struct rw_semaphore rw_sema;
} obj;
MALI_DEBUG_CODE(
/** original flags for debug checking */
_mali_osk_lock_flags_t orig_flags;
_mali_osk_lock_mode_t locked_as;
); /* MALI_DEBUG_CODE */
};
_mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial, u32 order )
{
_mali_osk_lock_t *lock = NULL;
/* Validate parameters: */
/* Flags acceptable */
MALI_DEBUG_ASSERT( 0 == ( flags & ~(_MALI_OSK_LOCKFLAG_SPINLOCK
| _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ
| _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE
| _MALI_OSK_LOCKFLAG_READERWRITER
| _MALI_OSK_LOCKFLAG_ORDERED
| _MALI_OSK_LOCKFLAG_ONELOCK )) );
/* Spinlocks are always non-interruptable */
MALI_DEBUG_ASSERT( (((flags & _MALI_OSK_LOCKFLAG_SPINLOCK) || (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ)) && (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE))
|| !(flags & _MALI_OSK_LOCKFLAG_SPINLOCK));
/* Parameter initial SBZ - for future expansion */
MALI_DEBUG_ASSERT( 0 == initial );
lock = kmalloc(sizeof(_mali_osk_lock_t), GFP_KERNEL);
if ( NULL == lock )
{
return lock;
}
/* Determine type of mutex: */
/* defaults to interruptable mutex if no flags are specified */
if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK) )
{
/* Non-interruptable Spinlocks override all others */
lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN;
spin_lock_init( &lock->obj.spinlock );
}
else if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ ) )
{
lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ;
lock->flags = 0;
spin_lock_init( &lock->obj.spinlock );
}
else if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE)
&& (flags & _MALI_OSK_LOCKFLAG_READERWRITER) )
{
lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW;
init_rwsem( &lock->obj.rw_sema );
}
else
{
/* Usual mutex types */
if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE) )
{
lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT;
}
else
{
lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX;
}
/* Initially unlocked */
sema_init( &lock->obj.sema, 1 );
}
MALI_DEBUG_CODE(
/* Debug tracking of flags */
lock->orig_flags = flags;
lock->locked_as = _MALI_OSK_LOCKMODE_UNDEF;
); /* MALI_DEBUG_CODE */
return lock;
}
_mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode)
{
_mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
/* Parameter validation */
MALI_DEBUG_ASSERT_POINTER( lock );
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
|| _MALI_OSK_LOCKMODE_RO == mode );
/* Only allow RO locks when the initial object was a Reader/Writer lock
* Since information is lost on the internal locktype, we use the original
* information, which is only stored when built for DEBUG */
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
|| (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
switch ( lock->type )
{
case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
spin_lock(&lock->obj.spinlock);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
spin_lock_irqsave(&lock->obj.spinlock, lock->flags);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
if ( down_interruptible(&lock->obj.sema) )
{
err = _MALI_OSK_ERR_RESTARTSYSCALL;
}
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
down(&lock->obj.sema);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
if (mode == _MALI_OSK_LOCKMODE_RO)
{
down_read(&lock->obj.rw_sema);
}
else
{
down_write(&lock->obj.rw_sema);
}
break;
default:
/* Reaching here indicates a programming error, so you will not get here
* on non-DEBUG builds */
MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
break;
}
/* DEBUG tracking of previously locked state - occurs after lock obtained */
MALI_DEBUG_CODE(
if ( _MALI_OSK_ERR_OK == err )
{
/* Assert that this is not currently locked */
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_UNDEF == lock->locked_as );
lock->locked_as = mode;
}
); /* MALI_DEBUG_CODE */
return err;
}
void _mali_osk_lock_signal( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode )
{
/* Parameter validation */
MALI_DEBUG_ASSERT_POINTER( lock );
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
|| _MALI_OSK_LOCKMODE_RO == mode );
/* Only allow RO locks when the initial object was a Reader/Writer lock
* Since information is lost on the internal locktype, we use the original
* information, which is only stored when built for DEBUG */
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
|| (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
/* For DEBUG only, assert that we previously locked this, and in the same way (RW/RO) */
MALI_DEBUG_ASSERT( mode == lock->locked_as );
/* DEBUG tracking of previously locked state - occurs before lock released */
MALI_DEBUG_CODE( lock->locked_as = _MALI_OSK_LOCKMODE_UNDEF );
switch ( lock->type )
{
case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
spin_unlock(&lock->obj.spinlock);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
spin_unlock_irqrestore(&lock->obj.spinlock, lock->flags);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
/* FALLTHROUGH */
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
up(&lock->obj.sema);
break;
case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
if (mode == _MALI_OSK_LOCKMODE_RO)
{
up_read(&lock->obj.rw_sema);
}
else
{
up_write(&lock->obj.rw_sema);
}
break;
default:
/* Reaching here indicates a programming error, so you will not get here
* on non-DEBUG builds */
MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
break;
}
}
void _mali_osk_lock_term( _mali_osk_lock_t *lock )
{
/* Parameter validation */
MALI_DEBUG_ASSERT_POINTER( lock );
/* For DEBUG only, assert that this is not currently locked */
MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_UNDEF == lock->locked_as );
/* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
kfree(lock);
}

View File

@@ -0,0 +1,636 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
* Copyright (C) 2011 STMicroelectronics R&D Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_low_level_mem.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
/* needed to detect kernel version specific code */
#include <linux/version.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "mali_osk.h"
#include "mali_ukk.h" /* required to hook in _mali_ukk_mem_mmap handling */
#include "mali_kernel_common.h"
#include "mali_kernel_linux.h"
#ifndef CONFIG_PARANOID_MEM_BARRIERS
#define CONFIG_PARANOID_MEM_BARRIERS 1
#endif
static void mali_kernel_memory_vma_open(struct vm_area_struct * vma);
static void mali_kernel_memory_vma_close(struct vm_area_struct * vma);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf);
#else
static unsigned long mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address);
#endif
extern volatile int *stbus_system_memory_barrier;
typedef struct mali_vma_usage_tracker
{
int references;
u32 cookie;
} mali_vma_usage_tracker;
/* Linked list structure to hold details of all OS allocations in a particular
* mapping
*/
struct AllocationList
{
struct AllocationList *next;
u32 offset;
u32 physaddr;
};
typedef struct AllocationList AllocationList;
/* Private structure to store details of a mapping region returned
* from _mali_osk_mem_mapregion_init
*/
struct MappingInfo
{
struct vm_area_struct *vma;
mali_vma_usage_tracker *vma_usage_tracker;
struct AllocationList *list;
};
typedef struct MappingInfo MappingInfo;
static u32 _kernel_page_allocate(void);
static void _kernel_page_release(u32 physical_address);
static AllocationList * _allocation_list_item_get(void);
static void _allocation_list_item_release(AllocationList * item);
/* Variable declarations */
spinlock_t allocation_list_spinlock;
static AllocationList * pre_allocated_memory = (AllocationList*) NULL ;
static int pre_allocated_memory_size_current = 0;
#ifdef MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB
static int pre_allocated_memory_size_max = MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB * 1024 * 1024;
#else
static int pre_allocated_memory_size_max = 6 * 1024 * 1024; /* 6 MiB */
#endif
static struct vm_operations_struct mali_kernel_vm_ops =
{
.open = mali_kernel_memory_vma_open,
.close = mali_kernel_memory_vma_close,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
.fault = mali_kernel_memory_cpu_page_fault_handler
#else
.nopfn = mali_kernel_memory_cpu_page_fault_handler
#endif
};
void mali_osk_low_level_mem_init(void)
{
spin_lock_init( &allocation_list_spinlock );
pre_allocated_memory = (AllocationList*) NULL ;
}
void mali_osk_low_level_mem_term(void)
{
while ( NULL != pre_allocated_memory )
{
AllocationList *item;
item = pre_allocated_memory;
pre_allocated_memory = item->next;
_kernel_page_release(item->physaddr);
_mali_osk_free( item );
}
pre_allocated_memory_size_current = 0;
}
static u32 _kernel_page_allocate(void)
{
struct page *new_page;
u32 linux_phys_addr;
new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN | __GFP_COLD);
if ( NULL == new_page )
{
return 0;
}
/* Ensure page is flushed from CPU caches. */
linux_phys_addr = dma_map_page(NULL, new_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
#if defined(__sh__)
_mali_osk_mem_barrier();
#endif
return linux_phys_addr;
}
static void _kernel_page_release(u32 physical_address)
{
struct page *unmap_page;
#if 1
dma_unmap_page(NULL, physical_address, PAGE_SIZE, DMA_BIDIRECTIONAL);
#endif
unmap_page = pfn_to_page( physical_address >> PAGE_SHIFT );
MALI_DEBUG_ASSERT_POINTER( unmap_page );
__free_page( unmap_page );
}
static AllocationList * _allocation_list_item_get(void)
{
AllocationList *item = NULL;
unsigned long flags;
spin_lock_irqsave(&allocation_list_spinlock,flags);
if ( pre_allocated_memory )
{
item = pre_allocated_memory;
pre_allocated_memory = pre_allocated_memory->next;
pre_allocated_memory_size_current -= PAGE_SIZE;
spin_unlock_irqrestore(&allocation_list_spinlock,flags);
return item;
}
spin_unlock_irqrestore(&allocation_list_spinlock,flags);
item = _mali_osk_malloc( sizeof(AllocationList) );
if ( NULL == item)
{
return NULL;
}
item->physaddr = _kernel_page_allocate();
if ( 0 == item->physaddr )
{
/* Non-fatal error condition, out of memory. Upper levels will handle this. */
_mali_osk_free( item );
return NULL;
}
return item;
}
static void _allocation_list_item_release(AllocationList * item)
{
unsigned long flags;
spin_lock_irqsave(&allocation_list_spinlock,flags);
if ( pre_allocated_memory_size_current < pre_allocated_memory_size_max)
{
item->next = pre_allocated_memory;
pre_allocated_memory = item;
pre_allocated_memory_size_current += PAGE_SIZE;
spin_unlock_irqrestore(&allocation_list_spinlock,flags);
return;
}
spin_unlock_irqrestore(&allocation_list_spinlock,flags);
_kernel_page_release(item->physaddr);
_mali_osk_free( item );
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf)
#else
static unsigned long mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
void __user * address;
address = vmf->virtual_address;
#endif
/*
* We always fail the call since all memory is pre-faulted when assigned to the process.
* Only the Mali cores can use page faults to extend buffers.
*/
MALI_DEBUG_PRINT(1, ("Page-fault in Mali memory region caused by the CPU.\n"));
MALI_DEBUG_PRINT(1, ("Tried to access %p (process local virtual address) which is not currently mapped to any Mali memory.\n", (void*)address));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
return VM_FAULT_SIGBUS;
#else
return NOPFN_SIGBUS;
#endif
}
static void mali_kernel_memory_vma_open(struct vm_area_struct * vma)
{
mali_vma_usage_tracker * vma_usage_tracker;
MALI_DEBUG_PRINT(4, ("Open called on vma %p\n", vma));
vma_usage_tracker = (mali_vma_usage_tracker*)vma->vm_private_data;
vma_usage_tracker->references++;
return;
}
static void mali_kernel_memory_vma_close(struct vm_area_struct * vma)
{
_mali_uk_mem_munmap_s args = {0, };
mali_memory_allocation * descriptor;
mali_vma_usage_tracker * vma_usage_tracker;
MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma));
vma_usage_tracker = (mali_vma_usage_tracker*)vma->vm_private_data;
BUG_ON(!vma_usage_tracker);
BUG_ON(0 == vma_usage_tracker->references);
vma_usage_tracker->references--;
if (0 != vma_usage_tracker->references)
{
MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", vma_usage_tracker->references));
return;
}
/** @note args->context unused, initialized to 0.
* Instead, we use the memory_session from the cookie */
descriptor = (mali_memory_allocation *)vma_usage_tracker->cookie;
args.cookie = (u32)descriptor;
args.mapping = descriptor->mapping;
args.size = descriptor->size;
_mali_ukk_mem_munmap( &args );
/* vma_usage_tracker is free()d by _mali_osk_mem_mapregion_term().
* In the case of the memory engine, it is called as the release function that has been registered with the engine*/
}
void _mali_osk_mem_barrier( void )
{
/*
* Note: mb() is a NOP on ST SH4 architectures
*/
mb();
#if defined(__sh__) && (CONFIG_PARANOID_MEM_BARRIERS == 1)
/*
* This is what mb would have done but it is pretty useless on ST SoCs as
* the CPU sync will return as soon as STBus says the write has happened,
* but all writes are posted, so this doesn't mean the write has reached
* its target.
*/
__asm__ __volatile__ ("synco": : :"memory");
#endif
/*
* This ensures that any previous uncached writes, from the CPU to the
* memory interface the Linux kernel is mapped in to, have really reached
* DDR and are available to be read by the GPU. It is actually the read
* here which ensures the ordering, the write is just there to make sure the
* compiler doesn't optimize it out.
*
*/
(*stbus_system_memory_barrier)++;
}
mali_io_address _mali_osk_mem_mapioregion( u32 phys, u32 size, const char *description )
{
return (mali_io_address)ioremap_nocache(phys, size);
}
void _mali_osk_mem_unmapioregion( u32 phys, u32 size, mali_io_address virt )
{
iounmap((void*)virt);
}
mali_io_address _mali_osk_mem_allocioregion( u32 *phys, u32 size )
{
void * virt;
MALI_DEBUG_ASSERT_POINTER( phys );
MALI_DEBUG_ASSERT( 0 == (size & ~_MALI_OSK_CPU_PAGE_MASK) );
MALI_DEBUG_ASSERT( 0 != size );
/* dma_alloc_* uses a limited region of address space. On most arch/marchs
* 2 to 14 MiB is available. This should be enough for the page tables, which
* currently is the only user of this function. */
virt = dma_alloc_coherent(NULL, size, phys, GFP_KERNEL | GFP_DMA );
MALI_DEBUG_PRINT(3, ("Page table virt: 0x%x = dma_alloc_coherent(size:%d, phys:0x%x, )\n", virt, size, phys));
if ( NULL == virt )
{
MALI_DEBUG_PRINT(1, ("allocioregion: Failed to allocate Pagetable memory, size=0x%.8X\n", size ));
MALI_DEBUG_PRINT(1, ("Solution: When configuring and building linux kernel, set CONSISTENT_DMA_SIZE to be 14 MB.\n"));
return 0;
}
MALI_DEBUG_ASSERT( 0 == (*phys & ~_MALI_OSK_CPU_PAGE_MASK) );
return (mali_io_address)virt;
}
void _mali_osk_mem_freeioregion( u32 phys, u32 size, mali_io_address virt )
{
MALI_DEBUG_ASSERT_POINTER( (void*)virt );
MALI_DEBUG_ASSERT( 0 != size );
MALI_DEBUG_ASSERT( 0 == (phys & ( (1 << PAGE_SHIFT) - 1 )) );
dma_free_coherent(NULL, size, virt, phys);
}
_mali_osk_errcode_t inline _mali_osk_mem_reqregion( u32 phys, u32 size, const char *description )
{
return ((NULL == request_mem_region(phys, size, description)) ? _MALI_OSK_ERR_NOMEM : _MALI_OSK_ERR_OK);
}
void inline _mali_osk_mem_unreqregion( u32 phys, u32 size )
{
release_mem_region(phys, size);
}
u32 inline _mali_osk_mem_ioread32( volatile mali_io_address addr, u32 offset )
{
return ioread32(((u8*)addr) + offset);
}
void inline _mali_osk_mem_iowrite32( volatile mali_io_address addr, u32 offset, u32 val )
{
iowrite32(val, ((u8*)addr) + offset);
#if (CONFIG_PARANOID_MEM_BARRIERS == 1)
#if defined(__sh__)
__asm__ __volatile__ ("synco": : :"memory");
#endif
/*
* This readback ensures that the previous write must have reached the
* bus target it was intended for. The usual place this can catch you out
* is clearing interrupts, if the write to the clear register doesn't
* complete before the interrupt handler returns, the interrupt controller
* may still see the interrupt as asserted and the linux interrupt
* dispatcher will call the handler again spuriously.
*/
val = ioread32(((u8*)addr) + offset);
#endif
}
void _mali_osk_cache_flushall( void )
{
/** @note Cached memory is not currently supported in this implementation */
}
void _mali_osk_cache_ensure_uncached_range_flushed( void *uncached_mapping, u32 offset, u32 size )
{
/*
* On the SH4 the address we get here is a userspace address, for
* which we have no interface that can be used to flush the L2. So
* instead we flush pages during the map function when they are
* allocated from the kernel. However just for paranoia we put a
* bus barrier here.
*/
_mali_osk_mem_barrier();
}
_mali_osk_errcode_t _mali_osk_mem_mapregion_init( mali_memory_allocation * descriptor )
{
struct vm_area_struct *vma;
mali_vma_usage_tracker * vma_usage_tracker;
MappingInfo *mappingInfo;
if (NULL == descriptor) return _MALI_OSK_ERR_FAULT;
MALI_DEBUG_ASSERT( 0 != (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE) );
vma = (struct vm_area_struct*)descriptor->process_addr_mapping_info;
if (NULL == vma ) return _MALI_OSK_ERR_FAULT;
/* Re-write the process_addr_mapping_info */
mappingInfo = _mali_osk_calloc( 1, sizeof(MappingInfo) );
if ( NULL == mappingInfo ) return _MALI_OSK_ERR_FAULT;
vma_usage_tracker = _mali_osk_calloc( 1, sizeof(mali_vma_usage_tracker) );
if (NULL == vma_usage_tracker)
{
MALI_DEBUG_PRINT(2, ("Failed to allocate memory to track memory usage\n"));
_mali_osk_free( mappingInfo );
return _MALI_OSK_ERR_FAULT;
}
mappingInfo->vma = vma;
mappingInfo->vma_usage_tracker = vma_usage_tracker;
descriptor->process_addr_mapping_info = mappingInfo;
/* Do the va range allocation - in this case, it was done earlier, so we copy in that information */
descriptor->mapping = (void __user*)vma->vm_start;
/* list member is already NULL */
/*
set some bits which indicate that:
The memory is IO memory, meaning that no paging is to be performed and the memory should not be included in crash dumps
The memory is reserved, meaning that it's present and can never be paged out (see also previous entry)
*/
vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;
vma->vm_flags |= VM_DONTCOPY;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mali_kernel_vm_ops; /* Operations used on any memory system */
vma_usage_tracker->references = 1; /* set initial reference count to be 1 as vma_open won't be called for the first mmap call */
vma_usage_tracker->cookie = (u32)descriptor; /* cookie for munmap */
vma->vm_private_data = vma_usage_tracker;
return _MALI_OSK_ERR_OK;
}
void _mali_osk_mem_mapregion_term( mali_memory_allocation * descriptor )
{
mali_vma_usage_tracker * vma_usage_tracker;
MappingInfo *mappingInfo;
if (NULL == descriptor) return;
MALI_DEBUG_ASSERT( 0 != (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE) );
mappingInfo = (MappingInfo *)descriptor->process_addr_mapping_info;
MALI_DEBUG_ASSERT_POINTER( mappingInfo );
/* Linux does the right thing as part of munmap to remove the mapping
* All that remains is that we remove the vma_usage_tracker setup in init() */
/* vma_area_struct in descriptor and in vma_close can be different.
* Dereferencing vma to get tracker can fault, as kernel MIGHT have
* freed the vma_area_struct in the descriptor. Now vma_usage_tracker
* can be obtained from mappingInfo, which will be valid at this point.
*/
vma_usage_tracker = mappingInfo->vma_usage_tracker;
/* ASSERT that there are no allocations on the list. Unmap should've been
* called on all OS allocations. */
MALI_DEBUG_ASSERT( NULL == mappingInfo->list );
/* We only get called if mem_mapregion_init succeeded */
_mali_osk_free(vma_usage_tracker);
_mali_osk_free( mappingInfo );
return;
}
_mali_osk_errcode_t _mali_osk_mem_mapregion_map( mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size )
{
struct vm_area_struct *vma;
MappingInfo *mappingInfo;
if (NULL == descriptor) return _MALI_OSK_ERR_FAULT;
MALI_DEBUG_ASSERT_POINTER( phys_addr );
MALI_DEBUG_ASSERT( 0 != (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE) );
MALI_DEBUG_ASSERT( 0 == (size & ~_MALI_OSK_CPU_PAGE_MASK) );
MALI_DEBUG_ASSERT( 0 == (offset & ~_MALI_OSK_CPU_PAGE_MASK));
if (NULL == descriptor->mapping) return _MALI_OSK_ERR_INVALID_ARGS;
if (size > (descriptor->size - offset))
{
MALI_DEBUG_PRINT(1,("_mali_osk_mem_mapregion_map: virtual memory area not large enough to map physical 0x%x size %x into area 0x%x at offset 0x%xr\n",
*phys_addr, size, descriptor->mapping, offset));
return _MALI_OSK_ERR_FAULT;
}
mappingInfo = (MappingInfo *)descriptor->process_addr_mapping_info;
MALI_DEBUG_ASSERT_POINTER( mappingInfo );
vma = mappingInfo->vma;
if (NULL == vma ) return _MALI_OSK_ERR_FAULT;
MALI_DEBUG_PRINT(7, ("Process map: mapping 0x%08X to process address 0x%08lX length 0x%08X\n", *phys_addr, (long unsigned int)(descriptor->mapping + offset), size));
if ( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC == *phys_addr )
{
_mali_osk_errcode_t ret;
AllocationList *alloc_item;
u32 linux_phys_frame_num;
alloc_item = _allocation_list_item_get();
linux_phys_frame_num = alloc_item->physaddr >> PAGE_SHIFT;
ret = ( remap_pfn_range( vma, ((u32)descriptor->mapping) + offset, linux_phys_frame_num, size, vma->vm_page_prot) ) ? _MALI_OSK_ERR_FAULT : _MALI_OSK_ERR_OK;
if ( ret != _MALI_OSK_ERR_OK)
{
_allocation_list_item_release(alloc_item);
return ret;
}
/* Put our alloc_item into the list of allocations on success */
alloc_item->next = mappingInfo->list;
alloc_item->offset = offset;
/*alloc_item->physaddr = linux_phys_addr;*/
mappingInfo->list = alloc_item;
/* Write out new physical address on success */
*phys_addr = alloc_item->physaddr;
return ret;
}
/* Otherwise, Use the supplied physical address */
/* ASSERT that supplied phys_addr is page aligned */
MALI_DEBUG_ASSERT( 0 == ((*phys_addr) & ~_MALI_OSK_CPU_PAGE_MASK) );
return ( remap_pfn_range( vma, ((u32)descriptor->mapping) + offset, *phys_addr >> PAGE_SHIFT, size, vma->vm_page_prot) ) ? _MALI_OSK_ERR_FAULT : _MALI_OSK_ERR_OK;
}
void _mali_osk_mem_mapregion_unmap( mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t flags )
{
MappingInfo *mappingInfo;
if (NULL == descriptor) return;
MALI_DEBUG_ASSERT( 0 != (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE) );
MALI_DEBUG_ASSERT( 0 == (size & ~_MALI_OSK_CPU_PAGE_MASK) );
MALI_DEBUG_ASSERT( 0 == (offset & ~_MALI_OSK_CPU_PAGE_MASK) );
if (NULL == descriptor->mapping) return;
if (size > (descriptor->size - offset))
{
MALI_DEBUG_PRINT(1,("_mali_osk_mem_mapregion_unmap: virtual memory area not large enough to unmap size %x from area 0x%x at offset 0x%x\n",
size, descriptor->mapping, offset));
return;
}
mappingInfo = (MappingInfo *)descriptor->process_addr_mapping_info;
MALI_DEBUG_ASSERT_POINTER( mappingInfo );
if ( 0 != (flags & _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR) )
{
/* This physical RAM was allocated in _mali_osk_mem_mapregion_map and
* so needs to be unmapped
*/
while (size)
{
/* First find the allocation in the list of allocations */
AllocationList *alloc = mappingInfo->list;
AllocationList **prev = &(mappingInfo->list);
while (NULL != alloc && alloc->offset != offset)
{
prev = &(alloc->next);
alloc = alloc->next;
}
if (alloc == NULL) {
MALI_DEBUG_PRINT(1, ("Unmapping memory that isn't mapped\n"));
size -= _MALI_OSK_CPU_PAGE_SIZE;
offset += _MALI_OSK_CPU_PAGE_SIZE;
continue;
}
_kernel_page_release(alloc->physaddr);
/* Remove the allocation from the list */
*prev = alloc->next;
_mali_osk_free( alloc );
/* Move onto the next allocation */
size -= _MALI_OSK_CPU_PAGE_SIZE;
offset += _MALI_OSK_CPU_PAGE_SIZE;
}
}
/* Linux does the right thing as part of munmap to remove the mapping */
return;
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
* Copyright (C) 2011 STMicroelectronics R&D Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_mali.c
* Implementation of the OS abstraction layer which is specific for the Mali kernel device driver
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/stm/platform.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include "mali_kernel_common.h" /* MALI_xxx macros */
#include "mali_osk.h" /* kernel side OS functions */
#include "mali_uk_types.h"
#include "mali_kernel_linux.h" /* exports initialize/terminate_kernel_device() */
extern struct platform_device *mali_platform_device;
/* Help to convert platform device resources into mali resources */
struct mali_resource_properties
{
const char *name;
_mali_osk_resource_type_t type;
u32 has_irq;
u32 mmu_id;
};
struct mali_resource_properties mali_resource_table[] = {
{ "MALI400GP", MALI400GP, 1, 1 },
{ "MALI400PP-0", MALI400PP, 1, 2 },
{ "MALI400PP-1", MALI400PP, 1, 3 },
{ "MALI400PP-2", MALI400PP, 1, 4 },
{ "MALI400PP-3", MALI400PP, 1, 5 },
{ "MMU-1", MMU, 1, 1 },
{ "MMU-2", MMU, 1, 2 },
{ "MMU-3", MMU, 1, 3 },
{ "MMU-4", MMU, 1, 4 },
{ "MMU-5", MMU, 1, 5 },
{ "MALI400L2", MALI400L2, 0, 0 },
{ "OS_MEMORY", OS_MEMORY, 0, 0 },
{ "MEMORY", MEMORY, 0, 0 },
{ "EXTERNAL_MEMORY_RANGE", MEM_VALIDATION, 0, 0 }
};
/* is called from mali_kernel_constructor in common code */
_mali_osk_errcode_t _mali_osk_init( void )
{
if (0 != initialize_kernel_device()) MALI_ERROR(_MALI_OSK_ERR_FAULT);
mali_osk_low_level_mem_init();
MALI_SUCCESS;
}
/* is called from mali_kernel_deconstructor in common code */
void _mali_osk_term( void )
{
mali_osk_low_level_mem_term();
terminate_kernel_device();
}
static struct mali_resource_properties *get_resource_properties(const char *name)
{
int i;
for(i=0;i<ARRAY_SIZE(mali_resource_table);i++)
{
if(!strcmp(mali_resource_table[i].name,name))
return &mali_resource_table[i];
}
MALI_PRINT(("Cannot find resource name %s\n", name));
return NULL;
}
static int mali_get_mem_resources(_mali_osk_resource_t *resources, struct stm_mali_resource *mem_resources, int num_resources, int *index)
{
int n = 0;
while(n < num_resources)
{
struct mali_resource_properties *properties;
struct stm_mali_resource *mem_resource;
_mali_osk_resource_t *mali_resource = &resources[*index];
mem_resource = &mem_resources[n];
if(!(properties = get_resource_properties(mem_resource->name)))
return _MALI_OSK_ERR_FAULT;
mali_resource->type = properties->type;
mali_resource->base = mem_resource->start;
mali_resource->size = mem_resource->end - mem_resource->start + 1;
switch(properties->type)
{
case MEMORY:
case OS_MEMORY:
mali_resource->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE;
mali_resource->alloc_order = n;
break;
case MEM_VALIDATION:
mali_resource->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE;
break;
default:
MALI_PRINT(("Resource %s should not be passed as mem_resources\n",mem_resource->name));
return _MALI_OSK_ERR_FAULT;
}
MALI_DEBUG_PRINT(3, ("Constructed resources for %s\n",mem_resource->name));
mali_resource->description = mem_resource->name;
(*index)++;
n++;
}
return _MALI_OSK_ERR_OK;
}
_mali_osk_errcode_t _mali_osk_resources_init( _mali_osk_resource_t **arch_config, u32 *num_resources )
{
struct resource *platform_resource;
_mali_osk_resource_t *resources;
int n,resource_count;
struct stm_mali_config *mali_config = (struct stm_mali_config *)
mali_platform_device->dev.platform_data;
resource_count = mali_platform_device->num_resources +
mali_config->num_mem_resources +
mali_config->num_ext_resources;
resources = kzalloc((resource_count * sizeof(_mali_osk_resource_t)),GFP_KERNEL);
if(!resources)
MALI_ERROR(_MALI_OSK_ERR_NOMEM);
resource_count = 0;
n = 0;
while((platform_resource = platform_get_resource(mali_platform_device,IORESOURCE_MEM,n)) != NULL)
{
_mali_osk_resource_t *mali_resource = &resources[resource_count];
struct mali_resource_properties *properties;
if(!(properties = get_resource_properties(platform_resource->name)))
goto error;
mali_resource->type = properties->type;
mali_resource->base = platform_resource->start;
mali_resource->size = 0;
switch(properties->type)
{
case MEMORY:
case OS_MEMORY:
case MEM_VALIDATION:
MALI_PRINT(("Mali Memory resource %s should be passed in platfrom priv data not IORESOURCE_MEM\n",platform_resource->name));
goto error;
default:
break;
}
mali_resource->mmu_id = properties->mmu_id;
if(properties->has_irq)
{
int irq;
MALI_DEBUG_PRINT(3, ("finding IRQ for %s\n",platform_resource->name));
if((irq = platform_get_irq_byname(mali_platform_device,platform_resource->name)) < 0)
{
MALI_PRINT(("Unable to find IRQ resource for %s\n",platform_resource->name));
goto error;
}
MALI_DEBUG_PRINT(3, ("found IRQ %d for %s\n",irq,platform_resource->name));
mali_resource->irq = irq;
}
MALI_DEBUG_PRINT(3, ("Constructed resources for %s\n",platform_resource->name));
mali_resource->description = platform_resource->name;
resource_count++;
n++;
}
/* Memory resources */
/* Memory resources allocated by Linux kernel and Memory managed by
* mali driver memory allocator */
if (mali_config->mem)
mali_get_mem_resources(resources, mali_config->mem,
mali_config->num_mem_resources, &resource_count);
/* External memory regions for mali to directly render */
if (mali_config->ext_mem)
mali_get_mem_resources(resources, mali_config->ext_mem,
mali_config->num_ext_resources, &resource_count);
*num_resources = resource_count;
*arch_config = resources;
return _MALI_OSK_ERR_OK;
error:
kfree(resources);
*arch_config = NULL;
MALI_ERROR(_MALI_OSK_ERR_FAULT);
}
void _mali_osk_resources_term( _mali_osk_resource_t **arch_config, u32 num_resources )
{
kfree(*arch_config);
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_math.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include "mali_osk.h"
#include <linux/bitops.h>
u32 inline _mali_osk_clz( u32 input )
{
return 32-fls(input);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_memory.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include "mali_osk.h"
#include <linux/slab.h>
void inline *_mali_osk_calloc( u32 n, u32 size )
{
return kcalloc(n, size, GFP_KERNEL);
}
void inline *_mali_osk_malloc( u32 size )
{
return kmalloc(size, GFP_KERNEL);
}
void inline _mali_osk_free( void *ptr )
{
kfree(ptr);
}
void inline *_mali_osk_memcpy( void *dst, const void *src, u32 len )
{
return memcpy(dst, src, len);
}
void inline *_mali_osk_memset( void *s, u32 c, u32 n )
{
return memset(s, c, n);
}
mali_bool _mali_osk_mem_check_allocated( u32 max_allocated )
{
/* No need to prevent an out-of-memory dialogue appearing on Linux,
* so we always return MALI_TRUE.
*/
return MALI_TRUE;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_misc.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <linux/sched.h>
#include <linux/module.h>
#include "mali_osk.h"
void _mali_osk_dbgmsg( const char *fmt, ... )
{
va_list args;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... )
{
int res;
va_list args;
va_start(args, fmt);
res = vsnprintf(buf, (size_t)size, fmt, args);
va_end(args);
return res;
}
void _mali_osk_abort(void)
{
/* make a simple fault by dereferencing a NULL pointer */
*(int *)0 = 0;
}
void _mali_osk_break(void)
{
_mali_osk_abort();
}
u32 _mali_osk_get_pid(void)
{
/* Thread group ID is the process ID on Linux */
return (u32)current->tgid;
}
u32 _mali_osk_get_tid(void)
{
/* pid is actually identifying the thread on Linux */
return (u32)current->pid;
}

View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_notification.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include "mali_osk.h"
#include "mali_kernel_common.h"
/* needed to detect kernel version specific code */
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <linux/semaphore.h>
#else /* pre 2.6.26 the file was in the arch specific location */
#include <asm/semaphore.h>
#endif
/**
* Declaration of the notification queue object type
* Contains a linked list of notification pending delivery to user space.
* It also contains a wait queue of exclusive waiters blocked in the ioctl
* When a new notification is posted a single thread is resumed.
*/
struct _mali_osk_notification_queue_t_struct
{
struct semaphore mutex; /**< Mutex protecting the list */
wait_queue_head_t receive_queue; /**< Threads waiting for new entries to the queue */
struct list_head head; /**< List of notifications waiting to be picked up */
};
typedef struct _mali_osk_notification_wrapper_t_struct
{
struct list_head list; /**< Internal linked list variable */
_mali_osk_notification_t data; /**< Notification data */
} _mali_osk_notification_wrapper_t;
_mali_osk_notification_queue_t *_mali_osk_notification_queue_init( void )
{
_mali_osk_notification_queue_t * result;
result = (_mali_osk_notification_queue_t *)kmalloc(sizeof(_mali_osk_notification_queue_t), GFP_KERNEL);
if (NULL == result) return NULL;
sema_init(&result->mutex, 1);
init_waitqueue_head(&result->receive_queue);
INIT_LIST_HEAD(&result->head);
return result;
}
_mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size )
{
/* OPT Recycling of notification objects */
_mali_osk_notification_wrapper_t *notification;
notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size, GFP_KERNEL );
if (NULL == notification)
{
MALI_DEBUG_PRINT(1, ("Failed to create a notification object\n"));
return NULL;
}
/* Init the list */
INIT_LIST_HEAD(&notification->list);
if (0 != size)
{
notification->data.result_buffer = ((u8*)notification) + sizeof(_mali_osk_notification_wrapper_t);
}
else
{
notification->data.result_buffer = NULL;
}
/* set up the non-allocating fields */
notification->data.notification_type = type;
notification->data.result_buffer_size = size;
/* all ok */
return &(notification->data);
}
void _mali_osk_notification_delete( _mali_osk_notification_t *object )
{
_mali_osk_notification_wrapper_t *notification;
MALI_DEBUG_ASSERT_POINTER( object );
notification = container_of( object, _mali_osk_notification_wrapper_t, data );
/* Remove from the list */
list_del(&notification->list);
/* Free the container */
kfree(notification);
}
void _mali_osk_notification_queue_term( _mali_osk_notification_queue_t *queue )
{
MALI_DEBUG_ASSERT_POINTER( queue );
/* not much to do, just free the memory */
kfree(queue);
}
void _mali_osk_notification_queue_send( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object )
{
_mali_osk_notification_wrapper_t *notification;
MALI_DEBUG_ASSERT_POINTER( queue );
MALI_DEBUG_ASSERT_POINTER( object );
notification = container_of( object, _mali_osk_notification_wrapper_t, data );
/* lock queue access */
down(&queue->mutex);
/* add to list */
list_add_tail(&notification->list, &queue->head);
/* unlock the queue */
up(&queue->mutex);
/* and wake up one possible exclusive waiter */
wake_up(&queue->receive_queue);
}
static int _mali_notification_queue_is_empty( _mali_osk_notification_queue_t *queue )
{
int ret;
down(&queue->mutex);
ret = list_empty(&queue->head);
up(&queue->mutex);
return ret;
}
#if MALI_STATE_TRACKING
mali_bool _mali_osk_notification_queue_is_empty( _mali_osk_notification_queue_t *queue )
{
return _mali_notification_queue_is_empty(queue) ? MALI_TRUE : MALI_FALSE;
}
#endif
_mali_osk_errcode_t _mali_osk_notification_queue_dequeue( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result )
{
_mali_osk_errcode_t ret = _MALI_OSK_ERR_ITEM_NOT_FOUND;
_mali_osk_notification_wrapper_t *wrapper_object;
down(&queue->mutex);
if (!list_empty(&queue->head))
{
wrapper_object = list_entry(queue->head.next, _mali_osk_notification_wrapper_t, list);
*result = &(wrapper_object->data);
list_del_init(&wrapper_object->list);
ret = _MALI_OSK_ERR_OK;
}
up(&queue->mutex);
return ret;
}
_mali_osk_errcode_t _mali_osk_notification_queue_receive( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result )
{
/* check input */
MALI_DEBUG_ASSERT_POINTER( queue );
MALI_DEBUG_ASSERT_POINTER( result );
/* default result */
*result = NULL;
while (_MALI_OSK_ERR_OK != _mali_osk_notification_queue_dequeue(queue, result))
{
if (wait_event_interruptible(queue->receive_queue, !_mali_notification_queue_is_empty(queue)))
{
return _MALI_OSK_ERR_RESTARTSYSCALL;
}
}
return _MALI_OSK_ERR_OK; /* all ok */
}

View File

@@ -0,0 +1,195 @@
/**
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_pm.c
* Implementation of the callback functions from common power management
*/
#include <linux/sched.h>
#ifdef CONFIG_PM_RUNTIME
#include <linux/pm_runtime.h>
#endif /* CONFIG_PM_RUNTIME */
#include <linux/platform_device.h>
#include "mali_platform.h"
#include "mali_osk.h"
#include "mali_uk_types.h"
#include "mali_pmm.h"
#include "mali_ukk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_license.h"
#include "mali_kernel_pm.h"
#include "mali_device_pause_resume.h"
#include "mali_linux_pm.h"
#include "mali_linux_pm_testsuite.h"
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
#ifdef CONFIG_PM_RUNTIME
static int is_runtime =0;
#endif /* CONFIG_PM_RUNTIME */
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#if MALI_POWER_MGMT_TEST_SUITE
#ifdef CONFIG_PM
unsigned int mali_pmm_events_triggered_mask = 0;
#endif /* CONFIG_PM */
void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id mali_pmm_event)
{
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM
switch (mali_pmm_event)
{
case MALI_PMM_EVENT_JOB_QUEUED:
if (mali_job_scheduling_events_recording_on == 1)
{
mali_pmm_events_triggered_mask |= (1<<0);
}
break;
case MALI_PMM_EVENT_JOB_SCHEDULED:
if (mali_job_scheduling_events_recording_on == 1)
{
mali_pmm_events_triggered_mask |= (1<<1);
}
break;
case MALI_PMM_EVENT_JOB_FINISHED:
if (mali_job_scheduling_events_recording_on == 1)
{
mali_pmm_events_triggered_mask |= (1<<2);
mali_job_scheduling_events_recording_on = 0;
pwr_mgmt_status_reg = mali_pmm_events_triggered_mask;
}
break;
case MALI_PMM_EVENT_TIMEOUT:
if (mali_timeout_event_recording_on == 1)
{
pwr_mgmt_status_reg = (1<<3);
mali_timeout_event_recording_on = 0;
}
break;
default:
break;
}
#endif /* CONFIG_PM */
#endif /* MALI_LICENSE_IS_GPL */
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
/** This function is called when the Mali device has completed power up
* operation.
*/
void _mali_osk_pmm_power_up_done(mali_pmm_message_data data)
{
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM
is_wake_up_needed = 1;
wake_up_process(pm_thread);
MALI_DEBUG_PRINT(4, ("OSPMM: MALI OSK Power up Done\n" ));
return;
#endif /* CONFIG_PM */
#endif /* MALI_LICENSE_IS_GPL */
}
/** This function is called when the Mali device has completed power down
* operation.
*/
void _mali_osk_pmm_power_down_done(mali_pmm_message_data data)
{
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM
is_wake_up_needed = 1;
#if MALI_POWER_MGMT_TEST_SUITE
if (is_mali_pmu_present == 0)
{
pwr_mgmt_status_reg = _mali_pmm_cores_list();
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
wake_up_process(pm_thread);
MALI_DEBUG_PRINT(4, ("OSPMM: MALI Power down Done\n" ));
return;
#endif /* CONFIG_PM */
#endif /* MALI_LICENSE_IS_GPL */
}
/** This function is invoked when mali device is idle.
*/
_mali_osk_errcode_t _mali_osk_pmm_dev_idle(void)
{
_mali_osk_errcode_t err = 0;
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
err = pm_runtime_put_sync(&(mali_gpu_device.dev));
if(err)
{
MALI_DEBUG_PRINT(4, ("OSPMM: Error in _mali_osk_pmm_dev_idle\n" ));
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
#endif /* MALI_LICENSE_IS_GPL */
return err;
}
/** This funtion is invoked when mali device needs to be activated.
*/
void _mali_osk_pmm_dev_activate(void)
{
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM_RUNTIME
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
int err = 0;
if(is_runtime == 0)
{
pm_suspend_ignore_children(&(mali_gpu_device.dev), true);
pm_runtime_enable(&(mali_gpu_device.dev));
pm_runtime_get_sync(&(mali_gpu_device.dev));
is_runtime = 1;
}
else
{
err = pm_runtime_get_sync(&(mali_gpu_device.dev));
}
if(err)
{
MALI_DEBUG_PRINT(4, ("OSPMM: Error in _mali_osk_pmm_dev_activate\n" ));
}
#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */
#endif /* CONFIG_PM_RUNTIME */
#endif /* MALI_LICENSE_IS_GPL */
}
void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data)
{
#if MALI_LICENSE_IS_GPL
#ifdef CONFIG_PM
is_wake_up_needed = 1;
wake_up_process(dvfs_pm_thread);
MALI_DEBUG_PRINT(4, ("OSPMM: MALI OSK DVFS Operation done\n" ));
return;
#endif /* CONFIG_PM */
#endif /* MALI_LICENSE_IS_GPL */
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_specific.h
* Defines per-OS Kernel level specifics, such as unusual workarounds for
* certain OSs.
*/
#ifndef __MALI_OSK_SPECIFIC_H__
#define __MALI_OSK_SPECIFIC_H__
#ifdef __cplusplus
extern "C"
{
#endif
#define MALI_STATIC_INLINE static inline
#define MALI_NON_STATIC_INLINE inline
#ifdef __cplusplus
}
#endif
#endif /* __MALI_OSK_SPECIFIC_H__ */

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_time.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include "mali_osk.h"
#include <linux/jiffies.h>
#include <linux/time.h>
#include <asm/delay.h>
int _mali_osk_time_after( u32 ticka, u32 tickb )
{
return time_after((unsigned long)ticka, (unsigned long)tickb);
}
u32 _mali_osk_time_mstoticks( u32 ms )
{
return msecs_to_jiffies(ms);
}
u32 _mali_osk_time_tickstoms( u32 ticks )
{
return jiffies_to_msecs(ticks);
}
u32 _mali_osk_time_tickcount( void )
{
return jiffies;
}
void _mali_osk_time_ubusydelay( u32 usecs )
{
udelay(usecs);
}
u64 _mali_osk_time_get_ns( void )
{
struct timespec tsval;
getnstimeofday(&tsval);
return (u64)timespec_to_ns(&tsval);
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_osk_timers.c
* Implementation of the OS abstraction layer for the kernel device driver
*/
#include <linux/timer.h>
#include <linux/slab.h>
#include "mali_osk.h"
#include "mali_kernel_common.h"
struct _mali_osk_timer_t_struct
{
struct timer_list timer;
};
typedef void (*timer_timeout_function_t)(unsigned long);
_mali_osk_timer_t *_mali_osk_timer_init(void)
{
_mali_osk_timer_t *t = (_mali_osk_timer_t*)kmalloc(sizeof(_mali_osk_timer_t), GFP_KERNEL);
if (NULL != t) init_timer(&t->timer);
return t;
}
void _mali_osk_timer_add( _mali_osk_timer_t *tim, u32 ticks_to_expire )
{
MALI_DEBUG_ASSERT_POINTER(tim);
tim->timer.expires = _mali_osk_time_tickcount() + ticks_to_expire;
add_timer(&(tim->timer));
}
void _mali_osk_timer_mod( _mali_osk_timer_t *tim, u32 expiry_tick)
{
MALI_DEBUG_ASSERT_POINTER(tim);
mod_timer(&(tim->timer), expiry_tick);
}
void _mali_osk_timer_del( _mali_osk_timer_t *tim )
{
MALI_DEBUG_ASSERT_POINTER(tim);
del_timer_sync(&(tim->timer));
}
void _mali_osk_timer_setcallback( _mali_osk_timer_t *tim, _mali_osk_timer_callback_t callback, void *data )
{
MALI_DEBUG_ASSERT_POINTER(tim);
tim->timer.data = (unsigned long)data;
tim->timer.function = (timer_timeout_function_t)callback;
}
void _mali_osk_timer_term( _mali_osk_timer_t *tim )
{
MALI_DEBUG_ASSERT_POINTER(tim);
kfree(tim);
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <linux/slab.h> /* memort allocation functions */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
#include "mali_ukk_wrappers.h"
int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs)
{
_mali_uk_get_api_version_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
if (0 != get_user(kargs.version, &uargs->version)) return -EFAULT;
kargs.ctx = session_data;
err = _mali_ukk_get_api_version(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT;
if (0 != put_user(kargs.compatible, &uargs->compatible)) return -EFAULT;
return 0;
}
int get_system_info_size_wrapper(struct mali_session_data *session_data, _mali_uk_get_system_info_size_s __user *uargs)
{
_mali_uk_get_system_info_size_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_get_system_info_size(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT;
return 0;
}
int get_system_info_wrapper(struct mali_session_data *session_data, _mali_uk_get_system_info_s __user *uargs)
{
_mali_uk_get_system_info_s kargs;
_mali_osk_errcode_t err;
_mali_system_info *system_info_user;
_mali_system_info *system_info_kernel;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
if (0 != get_user(kargs.system_info, &uargs->system_info)) return -EFAULT;
if (0 != get_user(kargs.size, &uargs->size)) return -EFAULT;
/* A temporary kernel buffer for the system_info datastructure is passed through the system_info
* member. The ukk_private member will point to the user space destination of this buffer so
* that _mali_ukk_get_system_info() can correct the pointers in the system_info correctly
* for user space.
*/
system_info_kernel = kmalloc(kargs.size, GFP_KERNEL);
if (NULL == system_info_kernel) return -EFAULT;
system_info_user = kargs.system_info;
kargs.system_info = system_info_kernel;
kargs.ukk_private = (u32)system_info_user;
kargs.ctx = session_data;
err = _mali_ukk_get_system_info(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
kfree(system_info_kernel);
return map_errcode(err);
}
if (0 != copy_to_user(system_info_user, system_info_kernel, kargs.size))
{
kfree(system_info_kernel);
return -EFAULT;
}
kfree(system_info_kernel);
return 0;
}
int wait_for_notification_wrapper(struct mali_session_data *session_data, _mali_uk_wait_for_notification_s __user *uargs)
{
_mali_uk_wait_for_notification_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_wait_for_notification(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if(_MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS != kargs.type)
{
kargs.ctx = NULL; /* prevent kernel address to be returned to user space */
if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_wait_for_notification_s))) return -EFAULT;
}
else
{
if (0 != put_user(kargs.type, &uargs->type)) return -EFAULT;
}
return 0;
}
int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_post_notification_s __user *uargs)
{
_mali_uk_post_notification_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
if (0 != get_user(kargs.type, &uargs->type))
{
return -EFAULT;
}
err = _mali_ukk_post_notification(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
return 0;
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
#include "mali_ukk_wrappers.h"
int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs)
{
_mali_uk_gp_start_job_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (!access_ok(VERIFY_WRITE, uargs, sizeof(_mali_uk_gp_start_job_s)))
{
return -EFAULT;
}
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_gp_start_job_s))) return -EFAULT;
kargs.ctx = session_data;
err = _mali_ukk_gp_start_job(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
kargs.ctx = NULL; /* prevent kernel address to be returned to user space */
if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_gp_start_job_s)))
{
/*
* If this happens, then user space will not know that the job was actually started,
* and if we return a queued job, then user space will still think that one is still queued.
* This will typically lead to a deadlock in user space.
* This could however only happen if user space deliberately passes a user buffer which
* passes the access_ok(VERIFY_WRITE) check, but isn't fully writable at the time of copy_to_user().
* The official Mali driver will never attempt to do that, and kernel space should not be affected.
* That is why we do not bother to do a complex rollback in this very very very rare case.
*/
return -EFAULT;
}
return 0;
}
int gp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_abort_job_s __user *uargs)
{
_mali_uk_gp_abort_job_s kargs;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_gp_abort_job_s))) return -EFAULT;
kargs.ctx = session_data;
_mali_ukk_gp_abort_job(&kargs);
return 0;
}
int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs)
{
_mali_uk_get_gp_core_version_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_get_gp_core_version(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
/* no known transactions to roll-back */
if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT;
return 0;
}
int gp_suspend_response_wrapper(struct mali_session_data *session_data, _mali_uk_gp_suspend_response_s __user *uargs)
{
_mali_uk_gp_suspend_response_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_gp_suspend_response_s))) return -EFAULT;
kargs.ctx = session_data;
err = _mali_ukk_gp_suspend_response(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.cookie, &uargs->cookie)) return -EFAULT;
/* no known transactions to roll-back */
return 0;
}
int gp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_number_of_cores_s __user *uargs)
{
_mali_uk_get_gp_number_of_cores_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_get_gp_number_of_cores(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
/* no known transactions to roll-back */
if (0 != put_user(kargs.number_of_cores, &uargs->number_of_cores)) return -EFAULT;
return 0;
}

View File

@@ -0,0 +1,336 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
#include "mali_ukk_wrappers.h"
int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs)
{
_mali_uk_init_mem_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_init_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
if (0 != put_user(kargs.mali_address_base, &uargs->mali_address_base)) goto mem_init_rollback;
if (0 != put_user(kargs.memory_size, &uargs->memory_size)) goto mem_init_rollback;
return 0;
mem_init_rollback:
{
_mali_uk_term_mem_s kargs;
kargs.ctx = session_data;
err = _mali_ukk_term_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_init_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
int mem_term_wrapper(struct mali_session_data *session_data, _mali_uk_term_mem_s __user *uargs)
{
_mali_uk_term_mem_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_term_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
return 0;
}
int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user * argument)
{
_mali_uk_map_external_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_map_external_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_map_external_mem( &uk_args );
if (0 != put_user(uk_args.cookie, &argument->cookie))
{
if (_MALI_OSK_ERR_OK == err_code)
{
/* Rollback */
_mali_uk_unmap_external_mem_s uk_args_unmap;
uk_args_unmap.ctx = session_data;
uk_args_unmap.cookie = uk_args.cookie;
err_code = _mali_ukk_unmap_external_mem( &uk_args_unmap );
if (_MALI_OSK_ERR_OK != err_code)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_unmap_external_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user * argument)
{
_mali_uk_unmap_external_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_unmap_external_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_unmap_external_mem( &uk_args );
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0
int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument)
{
_mali_uk_release_ump_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_release_ump_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_release_ump_mem( &uk_args );
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user * argument)
{
_mali_uk_attach_ump_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_attach_ump_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_attach_ump_mem( &uk_args );
if (0 != put_user(uk_args.cookie, &argument->cookie))
{
if (_MALI_OSK_ERR_OK == err_code)
{
/* Rollback */
_mali_uk_release_ump_mem_s uk_args_unmap;
uk_args_unmap.ctx = session_data;
uk_args_unmap.cookie = uk_args.cookie;
err_code = _mali_ukk_release_ump_mem( &uk_args_unmap );
if (_MALI_OSK_ERR_OK != err_code)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_attach_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
/* Return the error that _mali_ukk_map_external_ump_mem produced */
return map_errcode(err_code);
}
#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER */
int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user * uargs)
{
_mali_uk_query_mmu_page_table_dump_size_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_query_mmu_page_table_dump_size(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT;
return 0;
}
int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user * uargs)
{
_mali_uk_dump_mmu_page_table_s kargs;
_mali_osk_errcode_t err;
void *buffer;
int rc = -EFAULT;
/* validate input */
MALI_CHECK_NON_NULL(uargs, -EINVAL);
/* the session_data pointer was validated by caller */
kargs.buffer = NULL;
/* get location of user buffer */
if (0 != get_user(buffer, &uargs->buffer)) goto err_exit;
/* get size of mmu page table info buffer from user space */
if ( 0 != get_user(kargs.size, &uargs->size) ) goto err_exit;
/* verify we can access the whole of the user buffer */
if (!access_ok(VERIFY_WRITE, buffer, kargs.size)) goto err_exit;
/* allocate temporary buffer (kernel side) to store mmu page table info */
kargs.buffer = _mali_osk_malloc(kargs.size);
if (NULL == kargs.buffer)
{
rc = -ENOMEM;
goto err_exit;
}
kargs.ctx = session_data;
err = _mali_ukk_dump_mmu_page_table(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
rc = map_errcode(err);
goto err_exit;
}
/* copy mmu page table info back to user space and update pointers */
if (0 != copy_to_user(uargs->buffer, kargs.buffer, kargs.size) ) goto err_exit;
if (0 != put_user((kargs.register_writes - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->register_writes)) goto err_exit;
if (0 != put_user((kargs.page_table_dump - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->page_table_dump)) goto err_exit;
if (0 != put_user(kargs.register_writes_size, &uargs->register_writes_size)) goto err_exit;
if (0 != put_user(kargs.page_table_dump_size, &uargs->page_table_dump_size)) goto err_exit;
rc = 0;
err_exit:
if (kargs.buffer) _mali_osk_free(kargs.buffer);
return rc;
}
int mem_get_big_block_wrapper( struct file * filp, _mali_uk_get_big_block_s __user * argument )
{
_mali_uk_get_big_block_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_get_big_block_s)) )
{
return -EFAULT;
}
/* This interface inserts something into the ukk_private word */
uk_args.ukk_private = (u32)filp;
uk_args.ctx = filp->private_data;
err_code = _mali_ukk_get_big_block( &uk_args );
/* Do not leak the private word back into user space */
uk_args.ukk_private = 0;
if ( _MALI_OSK_ERR_OK != err_code )
{
return map_errcode(err_code);
}
/* From this point on, we must roll-back any failing action to preserve the
* meaning of the U/K interface (e.g. when excluded) */
/* transfer response back to user space */
if ( 0 != copy_to_user(argument, &uk_args, sizeof(_mali_uk_get_big_block_s)) )
{
/* Roll-back - the _mali_uk_get_big_block call succeeded, so all
* values in uk_args will be correct */
_mali_uk_free_big_block_s uk_args_rollback = {0, };
uk_args_rollback.ctx = uk_args.ctx;
uk_args_rollback.cookie = uk_args.cookie;
err_code = _mali_ukk_free_big_block( &uk_args_rollback );
if ( _MALI_OSK_ERR_OK != err_code )
{
/* error in DEBUG and RELEASE */
MALI_PRINT_ERROR( ("Failed to rollback get_big_block: %.8X\n", (u32)err_code) );
}
return -EFAULT;
}
return 0;
}
int mem_free_big_block_wrapper(struct mali_session_data *session_data, _mali_uk_free_big_block_s __user * argument)
{
_mali_uk_free_big_block_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL );
/* get call arguments from user space. get_user returns 0 on success */
if ( 0 != get_user(uk_args.cookie, &argument->cookie) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_free_big_block( &uk_args );
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
#include "mali_ukk_wrappers.h"
int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs)
{
_mali_uk_pp_start_job_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (!access_ok(VERIFY_WRITE, uargs, sizeof(_mali_uk_pp_start_job_s)))
{
return -EFAULT;
}
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_start_job_s))) return -EFAULT;
kargs.ctx = session_data;
err = _mali_ukk_pp_start_job(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.returned_user_job_ptr, &uargs->returned_user_job_ptr) ||
0 != put_user(kargs.status, &uargs->status))
{
/*
* If this happens, then user space will not know that the job was actually started,
* and if we return a queued job, then user space will still think that one is still queued.
* This will typically lead to a deadlock in user space.
* This could however only happen if user space deliberately passes a user buffer which
* passes the access_ok(VERIFY_WRITE) check, but isn't fully writable at the time of copy_to_user().
* The official Mali driver will never attempt to do that, and kernel space should not be affected.
* That is why we do not bother to do a complex rollback in this very very very rare case.
*/
return -EFAULT;
}
return 0;
}
int pp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_abort_job_s __user *uargs)
{
_mali_uk_pp_abort_job_s kargs;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_abort_job_s))) return -EFAULT;
kargs.ctx = session_data;
_mali_ukk_pp_abort_job(&kargs);
return 0;
}
int pp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_number_of_cores_s __user *uargs)
{
_mali_uk_get_pp_number_of_cores_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_get_pp_number_of_cores(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.number_of_cores, &uargs->number_of_cores)) return -EFAULT;
return 0;
}
int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_core_version_s __user *uargs)
{
_mali_uk_get_pp_core_version_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_get_pp_core_version(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT;
return 0;
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_session_manager.h"
#include "mali_ukk_wrappers.h"
int profiling_start_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_start_s __user *uargs)
{
_mali_uk_profiling_start_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_profiling_start_s)))
{
return -EFAULT;
}
kargs.ctx = session_data;
err = _mali_ukk_profiling_start(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
if (0 != put_user(kargs.limit, &uargs->limit))
{
return -EFAULT;
}
return 0;
}
int profiling_add_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_add_event_s __user *uargs)
{
_mali_uk_profiling_add_event_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_profiling_add_event_s)))
{
return -EFAULT;
}
kargs.ctx = session_data;
err = _mali_ukk_profiling_add_event(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
return 0;
}
int profiling_stop_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_stop_s __user *uargs)
{
_mali_uk_profiling_stop_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_profiling_stop(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
if (0 != put_user(kargs.count, &uargs->count))
{
return -EFAULT;
}
return 0;
}
int profiling_get_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_event_s __user *uargs)
{
_mali_uk_profiling_get_event_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
if (0 != get_user(kargs.index, &uargs->index))
{
return -EFAULT;
}
kargs.ctx = session_data;
err = _mali_ukk_profiling_get_event(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
kargs.ctx = NULL; /* prevent kernel address to be returned to user space */
if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_profiling_get_event_s)))
{
return -EFAULT;
}
return 0;
}
int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_clear_s __user *uargs)
{
_mali_uk_profiling_clear_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_profiling_clear(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
return 0;
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_ukk_wrappers.h
* Defines the wrapper functions for each user-kernel function
*/
#ifndef __MALI_UKK_WRAPPERS_H__
#define __MALI_UKK_WRAPPERS_H__
#include "mali_uk_types.h"
#include "mali_osk.h"
#ifdef __cplusplus
extern "C"
{
#endif
int get_system_info_size_wrapper(struct mali_session_data *session_data, _mali_uk_get_system_info_size_s __user *uargs);
int get_system_info_wrapper(struct mali_session_data *session_data, _mali_uk_get_system_info_s __user *uargs);
int wait_for_notification_wrapper(struct mali_session_data *session_data, _mali_uk_wait_for_notification_s __user *uargs);
int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs);
int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_post_notification_s __user *uargs);
int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs);
int mem_term_wrapper(struct mali_session_data *session_data, _mali_uk_term_mem_s __user *uargs);
int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user * argument);
int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user * argument);
int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user * uargs);
int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user * uargs);
#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0
int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user * argument);
int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument);
#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER */
int mem_get_big_block_wrapper( struct file * filp, _mali_uk_get_big_block_s __user * argument );
int mem_free_big_block_wrapper( struct mali_session_data *session_data, _mali_uk_free_big_block_s __user * argument);
int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs);
int pp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_abort_job_s __user *uargs);
int pp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_number_of_cores_s __user *uargs);
int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_core_version_s __user *uargs);
int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs);
int gp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_abort_job_s __user *uargs);
int gp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_number_of_cores_s __user *uargs);
int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs);
int gp_suspend_response_wrapper(struct mali_session_data *session_data, _mali_uk_gp_suspend_response_s __user *uargs);
int profiling_start_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_start_s __user *uargs);
int profiling_add_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_add_event_s __user *uargs);
int profiling_stop_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_stop_s __user *uargs);
int profiling_get_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_event_s __user *uargs);
int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_clear_s __user *uargs);
int vsync_event_report_wrapper(struct mali_session_data *session_data, _mali_uk_vsync_event_report_s __user *uargs);
int map_errcode( _mali_osk_errcode_t err );
#ifdef __cplusplus
}
#endif
#endif /* __MALI_UKK_WRAPPERS_H__ */

View File

@@ -0,0 +1,26 @@
/***********************************************************************
*
* File: malidrv_build_info.c
* Copyright (c) 2010 STMicroelectronics Limited.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
\***********************************************************************/
char *__malidrv_build_info(void)
{ return "malidrv:"
" SOC=" MALIDRV_SOC
" KERNELDIR=" MALIDRV_KERNELDIR
" MMAP_CACHED_PAGES=" MALIDRV_MMAP_CACHED_PAGES
" USING_MMU=" MALIDRV_USING_MMU
" USING_UMP=" MALIDRV_USING_UMP
" USING_MALI400=" MALIDRV_USING_MALI400
" USING_MALI400_L2_CACHE=" MALIDRV_USING_MALI400L2
" USING_MALI200=" MALIDRV_USING_MALI200
" USING_GP2=" MALIDRV_USING_MALIGP2
" API_VERSION=" MALIDRV_API_VERSION
" REVISION=" MALIDRV_SVN_REV
" BUILD_DATE=" MALIDRV_BUILD_DATE
;
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform.c
* Platform specific Mali driver functions for a default platform
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_platform.h"
_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource)
{
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type)
{
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerdown(u32 cores)
{
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerup(u32 cores)
{
MALI_SUCCESS;
}
void mali_gpu_utilization_handler(u32 utilization)
{
}
#if MALI_POWER_MGMT_TEST_SUITE
u32 pmu_get_power_up_down_info(void)
{
return 4095;
}
#endif

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform.c
* Platform specific Mali driver functions for a default platform
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_platform.h"
#include "mali_pmm.h"
static int is_run_time = 0;
_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource)
{
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type)
{
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerdown(u32 cores)
{
if(is_run_time == 1)
{
_mali_osk_pmm_dev_idle();
is_run_time =0;
}
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerup(u32 cores)
{
if(is_run_time == 0)
{
_mali_osk_pmm_dev_activate();
is_run_time = 1;
}
MALI_SUCCESS;
}
void mali_gpu_utilization_handler(u32 utilization)
{
}
#if MALI_POWER_MGMT_TEST_SUITE
u32 pmu_get_power_up_down_info(void)
{
return 4095;
}
#endif

View File

@@ -0,0 +1,388 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform.c
* Platform specific Mali driver functions for Mali 400 PMU hardware
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_platform.h"
#if USING_MALI_PMM
#include "mali_pmm.h"
/* Internal test on/off */
#define PMU_TEST 0
/** @brief PMU hardware info
*/
typedef struct platform_pmu
{
u32 reg_base_addr; /**< PMU registers base address */
u32 reg_size; /**< PMU registers size */
const char *name; /**< PMU name */
u32 irq_num; /**< PMU irq number */
mali_io_address reg_mapped; /**< IO-mapped pointer to registers */
} platform_pmu_t;
static platform_pmu_t *pmu_info = NULL;
/** @brief Register layout for hardware PMU
*/
typedef enum {
PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */
PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */
PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */
PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */
PMU_REG_ADDR_MGMT_INT_RAWSTAT = 0x10, /*< Interrupt raw status register */
PMU_REG_ADDR_MGMT_INT_STAT = 0x14, /*< Interrupt status register */
PMU_REG_ADDR_MGMT_INT_CLEAR = 0x18, /*< Interrupt clear register */
PMU_REG_ADDR_MGMT_SW_DELAY = 0x1C, /*< Software delay register */
PMU_REG_ADDR_MGMT_MASTER_PWR_UP = 0x24, /*< Master power up register */
PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x28, /*< Size of register space */
} pmu_reg_addr_mgmt_addr;
/* Internal functions */
u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address);
void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val);
mali_pmm_core_mask pmu_translate_cores_to_pmu(mali_pmm_core_mask cores);
#if PMU_TEST
void pmm_pmu_dump_regs( platform_pmu_t *pmu );
void pmm_pmu_test( platform_pmu_t *pmu, u32 cores );
#endif
#endif /* USING_MALI_PMM */
_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource)
{
#if USING_MALI_PMM
if( resource == NULL )
{
/* Nothing to set up for the system */
}
else if( resource->type == PMU )
{
if( (resource->base == 0) ||
(resource->description == NULL) )
{
/* NOTE: We currently don't care about any other resource settings */
MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Missing PMU set up information\n"));
MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
}
MALI_DEBUG_ASSERT( pmu_info == NULL );
pmu_info = (platform_pmu_t *)_mali_osk_malloc(sizeof(*pmu_info));
MALI_CHECK_NON_NULL( pmu_info, _MALI_OSK_ERR_NOMEM );
/* All values get 0 as default */
_mali_osk_memset(pmu_info, 0, sizeof(*pmu_info));
pmu_info->reg_base_addr = resource->base;
pmu_info->reg_size = (u32)PMU_REGISTER_ADDRESS_SPACE_SIZE;
pmu_info->name = resource->description;
pmu_info->irq_num = resource->irq;
if( _MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name) )
{
MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not request register region (0x%08X - 0x%08X) for %s\n",
pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name));
goto cleanup;
}
else
{
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: request_mem_region: (0x%08X - 0x%08X) for %s\n",
pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name));
}
pmu_info->reg_mapped = _mali_osk_mem_mapioregion( pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name );
if( 0 == pmu_info->reg_mapped )
{
MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not ioremap registers for %s .\n", pmu_info->name));
_mali_osk_mem_unreqregion( pmu_info->reg_base_addr, pmu_info->reg_size );
goto cleanup;
}
else
{
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) for %s\n",
(u32) pmu_info->reg_mapped,
((u32)pmu_info->reg_mapped)+ pmu_info->reg_size - 1,
pmu_info->name));
}
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: Mapping registers to %s\n", pmu_info->name));
#if PMU_TEST
pmu_test(pmu_info, (MALI_PMM_CORE_GP));
pmu_test(pmu_info, (MALI_PMM_CORE_GP|MALI_PMM_CORE_L2|MALI_PMM_CORE_PP0));
#endif
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Initialized - %s\n", pmu_info->name) );
}
else
{
/* Didn't expect a different resource */
MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
}
MALI_SUCCESS;
cleanup:
_mali_osk_free(pmu_info);
pmu_info = NULL;
MALI_ERROR(_MALI_OSK_ERR_NOMEM);
#else
/* Nothing to do when not using PMM - as mali already on */
MALI_SUCCESS;
#endif
}
_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type)
{
#if USING_MALI_PMM
if( type == NULL )
{
/* Nothing to tear down for the system */
}
else if (*type == PMU)
{
if( pmu_info )
{
_mali_osk_mem_unmapioregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->reg_mapped);
_mali_osk_mem_unreqregion(pmu_info->reg_base_addr, pmu_info->reg_size);
_mali_osk_free(pmu_info);
pmu_info = NULL;
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Terminated PMU\n") );
}
}
else
{
/* Didn't expect a different resource */
MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
}
MALI_SUCCESS;
#else
/* Nothing to do when not using PMM */
MALI_SUCCESS;
#endif
}
_mali_osk_errcode_t mali_platform_powerdown(u32 cores)
{
#if USING_MALI_PMM
u32 stat;
u32 timeout;
u32 cores_pmu;
MALI_DEBUG_ASSERT_POINTER(pmu_info);
MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power down (0x%x)\n", cores) );
cores_pmu = pmu_translate_cores_to_pmu(cores);
pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_DOWN, cores_pmu );
/* Wait for cores to be powered down */
timeout = 10; /* 10ms */
do
{
/* Get status of sleeping cores */
stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS );
stat &= cores_pmu;
if( stat == cores_pmu ) break; /* All cores we wanted are now asleep */
_mali_osk_time_ubusydelay(1000); /* 1ms */
timeout--;
} while( timeout > 0 );
if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT);
MALI_SUCCESS;
#else
/* Nothing to do when not using PMM */
MALI_SUCCESS;
#endif
}
_mali_osk_errcode_t mali_platform_powerup(u32 cores)
{
#if USING_MALI_PMM
u32 cores_pmu;
u32 stat;
u32 timeout;
MALI_DEBUG_ASSERT_POINTER(pmu_info);
MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */
MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power up (0x%x)\n", cores) );
/* Don't use interrupts - just poll status */
pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_INT_MASK, 0 );
cores_pmu = pmu_translate_cores_to_pmu(cores);
pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_UP, cores_pmu );
timeout = 10; /* 10ms */
do
{
/* Get status of sleeping cores */
stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS );
stat &= cores_pmu;
if( stat == 0 ) break; /* All cores we wanted are now awake */
_mali_osk_time_ubusydelay(1000); /* 1ms */
timeout--;
} while( timeout > 0 );
if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT);
MALI_SUCCESS;
#else
/* Nothing to do when not using PMM */
MALI_SUCCESS;
#endif
}
void mali_gpu_utilization_handler(u32 utilization)
{
}
#if USING_MALI_PMM
/***** INTERNAL *****/
/** @brief Internal PMU function to translate the cores bit mask
* into something the hardware PMU understands
*
* @param cores PMM cores bitmask
* @return PMU hardware cores bitmask
*/
u32 pmu_translate_cores_to_pmu(mali_pmm_core_mask cores)
{
/* For Mali 400 PMU the cores mask is already the same as what
* the hardware PMU expects.
* For other hardware, some translation can be done here, by
* translating the MALI_PMM_CORE_* bits into specific hardware
* bits
*/
return cores;
}
/** @brief Internal PMU function to read a PMU register
*
* @param pmu handle that identifies the PMU hardware
* @param relative_address relative PMU hardware address to read from
* @return 32-bit value that was read from the address
*/
u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address)
{
u32 read_val;
MALI_DEBUG_ASSERT_POINTER(pmu);
MALI_DEBUG_ASSERT((relative_address & 0x03) == 0);
MALI_DEBUG_ASSERT(relative_address < pmu->reg_size);
read_val = _mali_osk_mem_ioread32(pmu->reg_mapped, relative_address);
MALI_DEBUG_PRINT( 5, ("PMU: reg_read: %s Addr:0x%04X Val:0x%08x\n",
pmu->name, relative_address, read_val));
return read_val;
}
/** @brief Internal PMU function to write to a PMU register
*
* @param pmu handle that identifies the PMU hardware
* @param relative_address relative PMU hardware address to write to
* @param new_val new 32-bit value to write into the address
*/
void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val)
{
MALI_DEBUG_ASSERT_POINTER(pmu);
MALI_DEBUG_ASSERT((relative_address & 0x03) == 0);
MALI_DEBUG_ASSERT(relative_address < pmu->reg_size);
MALI_DEBUG_PRINT( 5, ("PMU: reg_write: %s Addr:0x%04X Val:0x%08x\n",
pmu->name, relative_address, new_val));
_mali_osk_mem_iowrite32(pmu->reg_mapped, relative_address, new_val);
}
#if MALI_POWER_MGMT_TEST_SUITE
u32 pmu_get_power_up_down_info(void)
{
return pmu_reg_read(pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS);
}
#endif /* MALI_POWER_MGMT_TEST_SUITE */
#endif /* USING_MALI_PMM */
#if USING_MALI_PMM && PMU_TEST
/***** TEST *****/
void pmu_dump_regs( platform_pmu_t *pmu )
{
u32 addr;
for( addr = 0x0; addr < PMU_REGISTER_ADDRESS_SPACE_SIZE; addr += 0x4 )
{
MALI_PRINT( ("PMU_REG: 0x%08x: 0x%04x\n", (addr + pmu->reg_base_addr), pmu_reg_read( pmu, addr ) ) );
}
}
/* This function is an internal test for the PMU without any Mali h/w interaction */
void pmu_test( platform_pmu_t *pmu, u32 cores )
{
u32 stat;
u32 timeout;
MALI_PRINT( ("PMU_TEST: Start\n") );
pmu_dump_regs( pmu );
MALI_PRINT( ("PMU_TEST: Power down cores: 0x%x\n", cores) );
_mali_pmm_pmu_power_down( pmu, cores, MALI_TRUE );
stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS );
MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == cores ? "SUCCESS" : "FAIL" ) );
pmu_dump_regs( pmu );
MALI_PRINT( ("PMU_TEST: Power up cores: 0x%x\n", cores) );
_mali_pmm_pmu_power_up( pmu, cores, MALI_FALSE );
MALI_PRINT( ("PMU_TEST: Waiting for power up...\n") );
timeout = 1000; /* 1 sec */
while( !_mali_pmm_pmu_irq_power_up(pmu) && timeout > 0 )
{
_mali_osk_time_ubusydelay(1000); /* 1ms */
timeout--;
}
MALI_PRINT( ("PMU_TEST: Waited %dms for interrupt\n", (1000-timeout)) );
stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS );
MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == 0 ? "SUCCESS" : "FAIL" ) );
_mali_pmm_pmu_irq_power_up_clear(pmu);
pmu_dump_regs( pmu );
MALI_PRINT( ("PMU_TEST: Finish\n") );
}
#endif /* USING_MALI_PMM && PMU_TEST */

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform.h
* Platform specific Mali driver functions
*/
#include "mali_osk.h"
#if USING_MALI_PMM
#include "mali_pmm.h"
#endif
#if !USING_MALI_PMM
/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */
#define MALI_PLATFORM_SYSTEM 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Platform specific setup and initialisation of MALI
*
* This is called from the entrypoint of the driver to initialize the platform
* When using PMM, it is also called from the PMM start up to initialise the
* system PMU
*
* @param resource This is NULL when called on first driver start up, else it will
* be a pointer to a PMU resource
* @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource);
/** @brief Platform specific deinitialisation of MALI
*
* This is called on the exit of the driver to terminate the platform
* When using PMM, it is also called from the PMM termination code to clean up the
* system PMU
*
* @param type This is NULL when called on driver exit, else it will
* be a pointer to a PMU resource type (not the full resource)
* @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type);
/** @brief Platform specific powerdown sequence of MALI
*
* Called as part of platform init if there is no PMM support, else the
* PMM will call it.
*
* @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will
* be a mask of cores to power down based on the mali_pmm_core_id enum
* @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_powerdown(u32 cores);
/** @brief Platform specific powerup sequence of MALI
*
* Called as part of platform deinit if there is no PMM support, else the
* PMM will call it.
*
* @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will
* be a mask of cores to power down based on the mali_pmm_core_id enum
* @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_powerup(u32 cores);
/** @brief Platform specific handling of GPU utilization data
*
* When GPU utilization data is enabled, this function will be
* periodically called.
*
* @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization.
*/
void mali_gpu_utilization_handler(u32 utilization);
#if USING_MALI_PMM
#if MALI_POWER_MGMT_TEST_SUITE
/** @brief function to get status of individual cores
*
* This function is used by power management test suite to get the status of powered up/down the number
* of cores
* @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization.
*/
u32 pmu_get_power_up_down_info(void);
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2010 ARM Limited. All rights reserved.
* Copyright (C) 2011 STMicroelectronics R&D Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform.c
* Platform specific Mali driver functions for a default platform
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_platform.h"
/* Use stubs for now */
_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing\n", __FUNCTION__));
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing\n", __FUNCTION__));
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerdown(u32 cores)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing\n", __FUNCTION__));
MALI_SUCCESS;
}
_mali_osk_errcode_t mali_platform_powerup(u32 cores)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing\n", __FUNCTION__));
MALI_SUCCESS;
}
void mali_gpu_utilization_handler(u32 utilization)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing\n", __FUNCTION__));
}
#if MALI_POWER_MGMT_TEST_SUITE
u32 pmu_get_power_up_down_info(void)
{
MALI_DEBUG_PRINT(3, ("[%s] Stub version, doing nothing, returning 4095\n", __FUNCTION__));
return 4095;
}
#endif

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _MALI200_REGS_H_
#define _MALI200_REGS_H_
/**
* Enum for management register addresses.
*/
enum mali200_mgmt_reg
{
MALI200_REG_ADDR_MGMT_VERSION = 0x1000,
MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR = 0x1004,
MALI200_REG_ADDR_MGMT_STATUS = 0x1008,
MALI200_REG_ADDR_MGMT_CTRL_MGMT = 0x100c,
MALI200_REG_ADDR_MGMT_INT_RAWSTAT = 0x1020,
MALI200_REG_ADDR_MGMT_INT_CLEAR = 0x1024,
MALI200_REG_ADDR_MGMT_INT_MASK = 0x1028,
MALI200_REG_ADDR_MGMT_INT_STATUS = 0x102c,
MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW = 0x1044,
MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS = 0x1050,
MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x1080,
MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x1084,
MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x108c,
MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x10a0,
MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x10a4,
MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x10ac,
MALI200_REG_SIZEOF_REGISTER_BANK = 0x10f0
};
#define MALI200_REG_VAL_PERF_CNT_ENABLE 1
enum mali200_mgmt_ctrl_mgmt {
MALI200_REG_VAL_CTRL_MGMT_STOP_BUS = (1<<0),
#if defined(USING_MALI200)
MALI200_REG_VAL_CTRL_MGMT_FLUSH_CACHES = (1<<3),
#endif
MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET = (1<<5),
MALI200_REG_VAL_CTRL_MGMT_START_RENDERING = (1<<6),
#if defined(USING_MALI400)
MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET = (1<<7),
#endif
};
enum mali200_mgmt_irq {
MALI200_REG_VAL_IRQ_END_OF_FRAME = (1<<0),
MALI200_REG_VAL_IRQ_END_OF_TILE = (1<<1),
MALI200_REG_VAL_IRQ_HANG = (1<<2),
MALI200_REG_VAL_IRQ_FORCE_HANG = (1<<3),
MALI200_REG_VAL_IRQ_BUS_ERROR = (1<<4),
MALI200_REG_VAL_IRQ_BUS_STOP = (1<<5),
MALI200_REG_VAL_IRQ_CNT_0_LIMIT = (1<<6),
MALI200_REG_VAL_IRQ_CNT_1_LIMIT = (1<<7),
MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR = (1<<8),
MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND = (1<<9),
MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW = (1<<10),
MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW = (1<<11),
MALI400PP_REG_VAL_IRQ_RESET_COMPLETED = (1<<12),
};
#if defined USING_MALI200
#define MALI200_REG_VAL_IRQ_MASK_ALL ((enum mali200_mgmt_irq) (\
MALI200_REG_VAL_IRQ_END_OF_FRAME |\
MALI200_REG_VAL_IRQ_END_OF_TILE |\
MALI200_REG_VAL_IRQ_HANG |\
MALI200_REG_VAL_IRQ_FORCE_HANG |\
MALI200_REG_VAL_IRQ_BUS_ERROR |\
MALI200_REG_VAL_IRQ_BUS_STOP |\
MALI200_REG_VAL_IRQ_CNT_0_LIMIT |\
MALI200_REG_VAL_IRQ_CNT_1_LIMIT |\
MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR))
#elif defined USING_MALI400
#define MALI200_REG_VAL_IRQ_MASK_ALL ((enum mali200_mgmt_irq) (\
MALI200_REG_VAL_IRQ_END_OF_FRAME |\
MALI200_REG_VAL_IRQ_END_OF_TILE |\
MALI200_REG_VAL_IRQ_HANG |\
MALI200_REG_VAL_IRQ_FORCE_HANG |\
MALI200_REG_VAL_IRQ_BUS_ERROR |\
MALI200_REG_VAL_IRQ_BUS_STOP |\
MALI200_REG_VAL_IRQ_CNT_0_LIMIT |\
MALI200_REG_VAL_IRQ_CNT_1_LIMIT |\
MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR |\
MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND |\
MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW |\
MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW |\
MALI400PP_REG_VAL_IRQ_RESET_COMPLETED))
#else
#error "No supported mali core defined"
#endif
#if defined USING_MALI200
#define MALI200_REG_VAL_IRQ_MASK_USED ((enum mali200_mgmt_irq) (\
MALI200_REG_VAL_IRQ_END_OF_FRAME |\
MALI200_REG_VAL_IRQ_HANG |\
MALI200_REG_VAL_IRQ_FORCE_HANG |\
MALI200_REG_VAL_IRQ_BUS_ERROR |\
MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR))
#elif defined USING_MALI400
#define MALI200_REG_VAL_IRQ_MASK_USED ((enum mali200_mgmt_irq) (\
MALI200_REG_VAL_IRQ_END_OF_FRAME |\
MALI200_REG_VAL_IRQ_HANG |\
MALI200_REG_VAL_IRQ_FORCE_HANG |\
MALI200_REG_VAL_IRQ_BUS_ERROR |\
MALI200_REG_VAL_IRQ_BUS_STOP |\
MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR |\
MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND |\
MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW |\
MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW))
#else
#error "No supported mali core defined"
#endif
#define MALI200_REG_VAL_IRQ_MASK_NONE ((enum mali200_mgmt_irq)(0))
enum mali200_mgmt_status {
MALI200_REG_VAL_STATUS_RENDERING_ACTIVE = (1<<0),
MALI200_REG_VAL_STATUS_BUS_STOPPED = (1<<4),
};
enum mali200_render_unit
{
MALI200_REG_ADDR_FRAME = 0x0000,
};
#if defined USING_MALI200
#define MALI200_NUM_REGS_FRAME ((0x04C/4)+1)
#elif defined USING_MALI400
#define MALI200_NUM_REGS_FRAME ((0x058/4)+1)
#else
#error "No supported mali core defined"
#endif
enum mali200_wb_unit {
MALI200_REG_ADDR_WB0 = 0x0100,
MALI200_REG_ADDR_WB1 = 0x0200,
MALI200_REG_ADDR_WB2 = 0x0300
};
/** The number of registers in one single writeback unit */
#ifndef MALI200_NUM_REGS_WBx
#define MALI200_NUM_REGS_WBx ((0x02C/4)+1)
#endif
/* This should be in the top 16 bit of the version register of Mali PP */
#if defined USING_MALI200
#define MALI_PP_PRODUCT_ID 0xC807
#elif defined USING_MALI400
#define MALI300_PP_PRODUCT_ID 0xCE07
#define MALI400_PP_PRODUCT_ID 0xCD07
#define MALI_PP_PRODUCT_ID MALI400_PP_PRODUCT_ID
#else
#error "No supported mali core defined"
#endif
#endif /* _MALI200_REGS_H_ */

View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _MALIGP2_CONROL_REGS_H_
#define _MALIGP2_CONROL_REGS_H_
/**
* These are the different geometry processor controll registers.
* Their usage is to control and monitor the operation of the
* Vertex Shader and the Polygon List Builer in the geometry processor.
* Addresses are in 32-bit word relative sizes.
* @see [P0081] "Geometry Processor Data Structures" for details
*/
typedef enum {
MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR = 0x00,
MALIGP2_REG_ADDR_MGMT_VSCL_END_ADDR = 0x04,
MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR = 0x08,
MALIGP2_REG_ADDR_MGMT_PLBUCL_END_ADDR = 0x0c,
MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR = 0x10,
MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR = 0x14,
MALIGP2_REG_ADDR_MGMT_CMD = 0x20,
MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT = 0x24,
MALIGP2_REG_ADDR_MGMT_INT_CLEAR = 0x28,
MALIGP2_REG_ADDR_MGMT_INT_MASK = 0x2C,
MALIGP2_REG_ADDR_MGMT_INT_STAT = 0x30,
MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW = 0x34,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x3C,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x40,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x44,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x48,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x4C,
MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x50,
MALIGP2_REG_ADDR_MGMT_STATUS = 0x68,
MALIGP2_REG_ADDR_MGMT_VERSION = 0x6C,
MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR_READ = 0x80,
MALIGP2_REG_ADDR_MGMT_PLBCL_START_ADDR_READ = 0x84,
MALIGP2_CONTR_AXI_BUS_ERROR_STAT = 0x94,
MALIGP2_REGISTER_ADDRESS_SPACE_SIZE = 0x98,
} maligp_reg_addr_mgmt_addr;
#define MALIGP2_REG_VAL_PERF_CNT_ENABLE 1
/**
* Commands to geometry processor.
* @see MALIGP2_CTRL_REG_CMD
*/
typedef enum
{
MALIGP2_REG_VAL_CMD_START_VS = (1<< 0),
MALIGP2_REG_VAL_CMD_START_PLBU = (1<< 1),
MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC = (1<< 4),
MALIGP2_REG_VAL_CMD_RESET = (1<< 5),
MALIGP2_REG_VAL_CMD_FORCE_HANG = (1<< 6),
MALIGP2_REG_VAL_CMD_STOP_BUS = (1<< 9),
#if defined(USING_MALI400)
MALI400GP_REG_VAL_CMD_SOFT_RESET = (1<<10),
#endif
} mgp_contr_reg_val_cmd;
/** @defgroup MALIGP2_IRQ
* Interrupt status of geometry processor.
* @see MALIGP2_CTRL_REG_INT_RAWSTAT, MALIGP2_REG_ADDR_MGMT_INT_CLEAR,
* MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_ADDR_MGMT_INT_STAT
* @{
*/
#define MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST (1 << 0)
#define MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST (1 << 1)
#define MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM (1 << 2)
#define MALIGP2_REG_VAL_IRQ_VS_SEM_IRQ (1 << 3)
#define MALIGP2_REG_VAL_IRQ_PLBU_SEM_IRQ (1 << 4)
#define MALIGP2_REG_VAL_IRQ_HANG (1 << 5)
#define MALIGP2_REG_VAL_IRQ_FORCE_HANG (1 << 6)
#define MALIGP2_REG_VAL_IRQ_PERF_CNT_0_LIMIT (1 << 7)
#define MALIGP2_REG_VAL_IRQ_PERF_CNT_1_LIMIT (1 << 8)
#define MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR (1 << 9)
#define MALIGP2_REG_VAL_IRQ_SYNC_ERROR (1 << 10)
#define MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR (1 << 11)
#if defined USING_MALI400
#define MALI400GP_REG_VAL_IRQ_AXI_BUS_STOPPED (1 << 12)
#define MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD (1 << 13)
#define MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD (1 << 14)
#define MALI400GP_REG_VAL_IRQ_RESET_COMPLETED (1 << 19)
#define MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW (1 << 20)
#define MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW (1 << 21)
#define MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS (1 << 22)
#elif !defined USING_MALI200
#error "No supported mali core defined"
#endif
/* Mask defining all IRQs in MaliGP2 */
#if defined USING_MALI200
#define MALIGP2_REG_VAL_IRQ_MASK_ALL \
(\
MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \
MALIGP2_REG_VAL_IRQ_VS_SEM_IRQ | \
MALIGP2_REG_VAL_IRQ_PLBU_SEM_IRQ | \
MALIGP2_REG_VAL_IRQ_HANG | \
MALIGP2_REG_VAL_IRQ_FORCE_HANG | \
MALIGP2_REG_VAL_IRQ_PERF_CNT_0_LIMIT | \
MALIGP2_REG_VAL_IRQ_PERF_CNT_1_LIMIT | \
MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \
MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \
MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR)
#elif defined USING_MALI400
#define MALIGP2_REG_VAL_IRQ_MASK_ALL \
(\
MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \
MALIGP2_REG_VAL_IRQ_VS_SEM_IRQ | \
MALIGP2_REG_VAL_IRQ_PLBU_SEM_IRQ | \
MALIGP2_REG_VAL_IRQ_HANG | \
MALIGP2_REG_VAL_IRQ_FORCE_HANG | \
MALIGP2_REG_VAL_IRQ_PERF_CNT_0_LIMIT | \
MALIGP2_REG_VAL_IRQ_PERF_CNT_1_LIMIT | \
MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \
MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \
MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR | \
MALI400GP_REG_VAL_IRQ_AXI_BUS_STOPPED | \
MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD | \
MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD | \
MALI400GP_REG_VAL_IRQ_RESET_COMPLETED | \
MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW | \
MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW | \
MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS)
#else
#error "No supported mali core defined"
#endif
/* Mask defining the IRQs in MaliGP2 which we use*/
#if defined USING_MALI200
#define MALIGP2_REG_VAL_IRQ_MASK_USED \
(\
MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \
MALIGP2_REG_VAL_IRQ_HANG | \
MALIGP2_REG_VAL_IRQ_FORCE_HANG | \
MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \
MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \
MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR)
#elif defined USING_MALI400
#define MALIGP2_REG_VAL_IRQ_MASK_USED \
(\
MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \
MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \
MALIGP2_REG_VAL_IRQ_HANG | \
MALIGP2_REG_VAL_IRQ_FORCE_HANG | \
MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \
MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \
MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR | \
MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD | \
MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD | \
MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW | \
MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW | \
MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS)
#else
#error "No supported mali core defined"
#endif
/* Mask defining non IRQs on MaliGP2*/
#define MALIGP2_REG_VAL_IRQ_MASK_NONE 0
/** }@ defgroup MALIGP2_IRQ*/
/** @defgroup MALIGP2_STATUS
* The different Status values to the geometry processor.
* @see MALIGP2_CTRL_REG_STATUS
* @{
*/
#define MALIGP2_REG_VAL_STATUS_VS_ACTIVE 0x0002
#define MALIGP2_REG_VAL_STATUS_BUS_STOPPED 0x0004
#define MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE 0x0008
#define MALIGP2_REG_VAL_STATUS_BUS_ERROR 0x0040
#define MALIGP2_REG_VAL_STATUS_WRITE_BOUND_ERR 0x0100
/** }@ defgroup MALIGP2_STATUS*/
#define MALIGP2_REG_VAL_STATUS_MASK_ACTIVE (\
MALIGP2_REG_VAL_STATUS_VS_ACTIVE|\
MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE)
#define MALIGP2_REG_VAL_STATUS_MASK_ERROR (\
MALIGP2_REG_VAL_STATUS_BUS_ERROR |\
MALIGP2_REG_VAL_STATUS_WRITE_BOUND_ERR )
/* This should be in the top 16 bit of the version register of gp.*/
#if defined(USING_MALI200)
#define MALI_GP_PRODUCT_ID 0xA07
#elif defined(USING_MALI400)
#define MALI300_GP_PRODUCT_ID 0xC07
#define MALI400_GP_PRODUCT_ID 0xB07
#define MALI_GP_PRODUCT_ID MALI400_GP_PRODUCT_ID
#else
#error "No supported mali core defined"
#endif
/**
* The different sources for instrumented on the geometry processor.
* @see MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC
*/
enum MALIGP2_cont_reg_perf_cnt_src {
MALIGP2_REG_VAL_PERF_CNT1_SRC_NUMBER_OF_VERTICES_PROCESSED = 0x0a,
};
#endif

View File

@@ -0,0 +1 @@
r2p2-01dev0