diff options
Diffstat (limited to 'drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c')
-rw-r--r-- | drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c | 2032 |
1 files changed, 2032 insertions, 0 deletions
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c new file mode 100644 index 00000000000..1db8f3ad5ab --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c @@ -0,0 +1,2032 @@ +/* + * 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_osk.h" +#include "mali_kernel_pp.h" +#include "mali_kernel_subsystem.h" +#include "mali_kernel_rendercore.h" +#include "mali_osk_list.h" +#if MALI_GPU_UTILIZATION +#include "mali_kernel_utilization.h" +#endif +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_kernel_profiling.h" +#endif +#if USING_MMU +#include "mali_kernel_mem_mmu.h" +#endif /* USING_MMU */ +#if defined USING_MALI400_L2_CACHE +#include "mali_kernel_l2_cache.h" +#endif /* USING_MALI400_L2_CACHE */ + +#define HANG_CHECK_MSECS_MIN 100 +#define HANG_CHECK_MSECS_MAX 2000 /* 2 secs */ +#define HANG_CHECK_MSECS_DEFAULT 500 /* 500 ms */ + +#define WATCHDOG_MSECS_MIN (2*HANG_CHECK_MSECS_MIN) +#define WATCHDOG_MSECS_MAX 3600000 /* 1 hour */ +#define WATCHDOG_MSECS_DEFAULT 900000 /* 15 mins */ + +/* max value that will be converted from jiffies to msecs and written to job->render_time_msecs */ +#define JOB_MAX_JIFFIES 100000 + +int mali_hang_check_interval = HANG_CHECK_MSECS_DEFAULT; +int mali_max_job_runtime = WATCHDOG_MSECS_DEFAULT; + +/* Subsystem entrypoints: */ +static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id); +static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id); +#if USING_MMU +static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); +#endif + + +static void mali_core_subsystem_cleanup_all_renderunits(struct mali_core_subsystem* subsys); +static void mali_core_subsystem_move_core_set_idle(struct mali_core_renderunit *core); + +static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem); +static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session); + +static void find_and_abort(mali_core_session* session, u32 abort_id); + +static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core); +#if USING_MMU +static void mali_core_subsystem_callback_schedule_wrapper(void* sub); +#endif +static void mali_core_subsystem_schedule(mali_core_subsystem*subsystem); +static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status); + +static void mali_core_renderunit_irq_handler_remove(struct mali_core_renderunit *core); + +static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data); +static void mali_core_irq_handler_bottom_half ( void *data ); + +#if USING_MMU +static void lock_subsystem(struct mali_core_subsystem * subsys); +static void unlock_subsystem(struct mali_core_subsystem * subsys); +#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 + * + * This subsystem is necessary for operations common to all rendercore + * subsystems. For example, mali_subsystem_mali200 and mali_subsystem_gp2 may + * share a mutex when RENDERCORES_USE_GLOBAL_MUTEX is non-zero. + */ +struct mali_kernel_subsystem mali_subsystem_rendercore= +{ + rendercore_subsystem_startup, /* startup */ + rendercore_subsystem_terminate, /* shutdown */ + NULL, /* load_complete */ + NULL, /* system_info_fill */ + NULL, /* session_begin */ + NULL, /* session_end */ +#if USING_MMU + rendercore_subsystem_broadcast_notification, /* broadcast_notification */ +#else + NULL, +#endif +#if MALI_STATE_TRACKING + NULL, /* dump_state */ +#endif +} ; + +static _mali_osk_lock_t *rendercores_global_mutex = NULL; +static u32 rendercores_global_mutex_is_held = 0; +static u32 rendercores_global_mutex_owner = 0; + +/** The 'dummy' rendercore subsystem to allow global subsystem mutex to be + * locked for all subsystems that extend the ''rendercore'' */ +static mali_core_subsystem rendercore_dummy_subsystem = {0,}; + +/* + * Rendercore Subsystem functions. + * + * These are exposed by mali_subsystem_rendercore + */ + +/** + * @brief Initialize the Rendercore subsystem. + * + * This must be called before any other subsystem that extends the + * ''rendercore'' may be initialized. For example, this must be called before + * the following functions: + * - mali200_subsystem_startup(), from mali_subsystem_mali200 + * - maligp_subsystem_startup(), from mali_subsystem_gp2 + * + * @note This function is separate from mali_core_subsystem_init(). They + * are related, in that mali_core_subsystem_init() may use the structures + * initialized by rendercore_subsystem_startup() + */ +static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id) +{ + rendercores_global_mutex_is_held = 0; + rendercores_global_mutex = _mali_osk_lock_init( + (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED), + 0, 129); + + if (NULL == rendercores_global_mutex) + { + MALI_PRINT_ERROR(("Failed: _mali_osk_lock_init\n")) ; + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + rendercore_dummy_subsystem.name = "Rendercore Global Subsystem"; /* On the constant pool, do not free */ + rendercore_dummy_subsystem.magic_nr = SUBSYSTEM_MAGIC_NR; /* To please the Subsystem Mutex code */ + +#if MALI_GPU_UTILIZATION + if (mali_utilization_init() != _MALI_OSK_ERR_OK) + { + _mali_osk_lock_term(rendercores_global_mutex); + rendercores_global_mutex = NULL; + MALI_PRINT_ERROR(("Failed: mali_utilization_init\n")) ; + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } +#endif + +#if MALI_TIMELINE_PROFILING_ENABLED + if (_mali_profiling_init() != _MALI_OSK_ERR_OK) + { + /* No biggie if we wheren't able to initialize the profiling */ + MALI_PRINT_ERROR(("Rendercore: Failed to initialize profiling, feature will be unavailable\n")) ; + } +#endif + + MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex initialized\n")) ; + MALI_SUCCESS; +} + +/** + * @brief Terminate the Rendercore subsystem. + * + * This must only be called \b after any other subsystem that extends the + * ''rendercore'' has been terminated. For example, this must be called \b after + * the following functions: + * - mali200_subsystem_terminate(), from mali_subsystem_mali200 + * - maligp_subsystem_terminate(), from mali_subsystem_gp2 + * + * @note This function is separate from mali_core_subsystem_cleanup(), though, + * the subsystems that extend ''rendercore'' must still call + * mali_core_subsystem_cleanup() when they terminate. + */ +static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id) +{ + /* Catch double-terminate */ + MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_profiling_term(); +#endif + +#if MALI_GPU_UTILIZATION + mali_utilization_term(); +#endif + + rendercore_dummy_subsystem.name = NULL; /* The original string was on the constant pool, do not free */ + rendercore_dummy_subsystem.magic_nr = 0; + + /* ASSERT that no-one's holding this */ + MALI_DEBUG_PRINT_ASSERT( 0 == rendercores_global_mutex_is_held, + ("Rendercores' Global Mutex was held at termination time. Have the subsystems that extend ''rendercore'' been terminated?\n") ); + + _mali_osk_lock_term( rendercores_global_mutex ); + rendercores_global_mutex = NULL; + + MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex terminated\n")) ; +} + + +#if USING_MMU +/** + * @brief Handle certain Rendercore subsystem broadcast notifications + * + * When RENDERCORES_USE_GLOBAL_MUTEX is non-zero, this handles the following messages: + * - MMU_KILL_STEP0_LOCK_SUBSYSTEM + * - MMU_KILL_STEP4_UNLOCK_SUBSYSTEM + * + * The purpose is to manage the Rendercode Global Mutex, which cannot be + * managed by any system that extends the ''rendercore''. + * + * All other messages must be handled by mali_core_subsystem_broadcast_notification() + * + * + * When RENDERCORES_USE_GLOBAL_MUTEX is 0, this function does nothing. + * Instead, the subsystem that extends the ''rendercore' \b must handle its + * own mutexes - refer to mali_core_subsystem_broadcast_notification(). + * + * Used currently only for signalling when MMU has a pagefault + */ +static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) +{ + switch(message) + { + case MMU_KILL_STEP0_LOCK_SUBSYSTEM: + lock_subsystem( &rendercore_dummy_subsystem ); + break; + case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: + unlock_subsystem( &rendercore_dummy_subsystem ); + break; + + case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: + /** FALLTHROUGH */ + case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: + /** FALLTHROUGH */ + case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: + break; + + default: + MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); + break; + } + +} +#endif + +/* + * Functions inherited by the subsystems that extend the ''rendercore''. + */ + +u32 mali_core_renderunit_register_read(mali_core_renderunit *core, u32 relative_address) +{ + u32 read_val; + + #if USING_MALI_PMM + if( core->state == CORE_OFF ) + { + MALI_PRINT_ERROR(("Core is OFF during read: Core:%s Addr:0x%04X\n", + core->description,relative_address)); + return 0xDEADBEEF; + } + #endif + + MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); + + if (mali_benchmark) return 0; + + if (relative_address >= core->size) + { + MALI_PRINT_ERROR(("Trying to read from illegal register: 0x%04x in core: %s\n", + relative_address, core->description)); + return 0xDEADBEEF; + } + + read_val = _mali_osk_mem_ioread32(core->registers_mapped, relative_address); + + MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read: Core:%s Addr:0x%04X Val:0x%08x\n", + core->description,relative_address, read_val)); + + return read_val; +} + +void mali_core_renderunit_register_read_array(mali_core_renderunit *core, + u32 relative_address, + u32 * result_array, + u32 nr_of_regs + ) +{ + /* NOTE Do not use burst reads against the registers */ + + u32 i; + + for(i=0; i<nr_of_regs; ++i) + { + result_array[i] = mali_core_renderunit_register_read(core, relative_address + i*4); + } + + MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read_array: Core:%s Addr:0x%04X Nr_regs: %u\n", + core->description,relative_address, nr_of_regs)); +} + +void mali_core_renderunit_register_write(mali_core_renderunit *core, u32 relative_address, u32 new_val) +{ + #if USING_MALI_PMM + if( core->state == CORE_OFF ) + { + MALI_PRINT_ERROR(("Core is OFF during write: Core:%s Addr:0x%04X Val:0x%08x\n", + core->description,relative_address, new_val)); + return; + } + #endif + + MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); + + if (mali_benchmark) return; + + if (relative_address >= core->size) + { + MALI_PRINT_ERROR(("Trying to write to illegal register: 0x%04x in core: %s", + relative_address, core->description)); + return; + } + + MALI_DEBUG_PRINT(6, ("mali_core_renderunit_register_write: Core:%s Addr:0x%04X Val:0x%08x\n", + core->description,relative_address, new_val)); + + _mali_osk_mem_iowrite32(core->registers_mapped, relative_address, new_val); +} + + +void mali_core_renderunit_register_write_array(mali_core_renderunit *core, + u32 relative_address, + u32 * source_array, + u32 nr_of_regs) +{ + + u32 i; + MALI_DEBUG_PRINT(6, ("Core: renderunit_register_write_array: Core:%s Addr:0x%04X Nr_regs: %u\n", + core->description,relative_address, nr_of_regs)); + + /* Do not use burst writes against the registers */ + + for( i = 0; i< nr_of_regs; i++) + { + mali_core_renderunit_register_write(core, relative_address + i*4, source_array[i]); + } +} + +void mali_core_renderunit_timeout_function_hang_detection(void *arg) +{ + mali_bool action = MALI_FALSE; + mali_core_renderunit * core; + + core = (mali_core_renderunit *) arg; + if( !core ) return; + + /* if NOT idle OR has TIMED_OUT */ + if ( !((CORE_WATCHDOG_TIMEOUT == core->state ) || (CORE_IDLE== core->state)) ) + { + core->state = CORE_HANG_CHECK_TIMEOUT; + action = MALI_TRUE; + } + + if(action) _mali_osk_irq_schedulework(core->irq); +} + + +void mali_core_renderunit_timeout_function(void *arg) +{ + mali_core_renderunit * core; + mali_bool is_watchdog; + + core = (mali_core_renderunit *)arg; + if( !core ) return; + + is_watchdog = MALI_TRUE; + if (mali_benchmark) + { + /* poll based core */ + mali_core_job *job; + job = core->current_job; + if ( (NULL != job) && + (0 != _mali_osk_time_after(job->watchdog_jiffies,_mali_osk_time_tickcount())) + ) + { + core->state = CORE_POLL; + is_watchdog = MALI_FALSE; + } + } + + if (is_watchdog) + { + MALI_DEBUG_PRINT(3, ("SW-Watchdog timeout: Core:%s\n", core->description)); + core->state = CORE_WATCHDOG_TIMEOUT; + } + + _mali_osk_irq_schedulework(core->irq); +} + +/* Used by external renderunit_create<> function */ +_mali_osk_errcode_t mali_core_renderunit_init(mali_core_renderunit * core) +{ + MALI_DEBUG_PRINT(5, ("Core: renderunit_init: Core:%s\n", core->description)); + + _MALI_OSK_INIT_LIST_HEAD(&core->list) ; + core->timer = _mali_osk_timer_init(); + if (NULL == core->timer) + { + MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init timer\n", core->description)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + _mali_osk_timer_setcallback(core->timer, mali_core_renderunit_timeout_function, (void *)core); + + core->timer_hang_detection = _mali_osk_timer_init(); + if (NULL == core->timer_hang_detection) + { + _mali_osk_timer_term(core->timer); + MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init hang detection timer\n", core->description)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + _mali_osk_timer_setcallback(core->timer_hang_detection, mali_core_renderunit_timeout_function_hang_detection, (void *)core); + +#if USING_MALI_PMM + /* Init no pending power downs */ + core->pend_power_down = MALI_FALSE; + + /* Register the core with the PMM - which powers it up */ + if (_MALI_OSK_ERR_OK != malipmm_core_register( core->pmm_id )) + { + _mali_osk_timer_term(core->timer); + _mali_osk_timer_term(core->timer_hang_detection); + MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot register with PMM\n", core->description)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } +#endif /* USING_MALI_PMM */ + + core->error_recovery = MALI_FALSE; + core->in_detach_function = MALI_FALSE; + core->state = CORE_IDLE; + core->current_job = NULL; + core->magic_nr = CORE_MAGIC_NR; +#if USING_MMU + core->mmu = NULL; +#endif /* USING_MMU */ + + MALI_SUCCESS; +} + +void mali_core_renderunit_term(mali_core_renderunit * core) +{ + MALI_DEBUG_PRINT(5, ("Core: renderunit_term: Core:%s\n", core->description)); + + if (NULL != core->timer) + { + _mali_osk_timer_term(core->timer); + core->timer = NULL; + } + if (NULL != core->timer_hang_detection) + { + _mali_osk_timer_term(core->timer_hang_detection); + core->timer_hang_detection = NULL; + } + +#if USING_MALI_PMM + /* Unregister the core with the PMM */ + malipmm_core_unregister( core->pmm_id ); +#endif +} + +/* Used by external renderunit_create<> function */ +_mali_osk_errcode_t mali_core_renderunit_map_registers(mali_core_renderunit *core) +{ + MALI_DEBUG_PRINT(3, ("Core: renderunit_map_registers: Core:%s\n", core->description)) ; + if( (0 == core->registers_base_addr) || + (0 == core->size) || + (NULL == core->description) + ) + { + MALI_PRINT_ERROR(("Missing fields in the core structure %u %u 0x%x;\n", core->registers_base_addr, core->size, core->description)); + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + + if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(core->registers_base_addr, core->size, core->description)) + { + MALI_PRINT_ERROR(("Could not request register region (0x%08X - 0x%08X) to core: %s\n", + core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + else + { + MALI_DEBUG_PRINT(6, ("Success: request_mem_region: (0x%08X - 0x%08X) Core:%s\n", + core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); + } + + core->registers_mapped = _mali_osk_mem_mapioregion( core->registers_base_addr, core->size, core->description ); + + if ( 0 == core->registers_mapped ) + { + MALI_PRINT_ERROR(("Could not ioremap registers for %s .\n", core->description)); + _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + else + { + MALI_DEBUG_PRINT(6, ("Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) Core:%s\n", + (u32) core->registers_mapped, + ((u32)core->registers_mapped)+ core->size - 1, + core->description)); + } + + MALI_DEBUG_PRINT(4, ("Success: Mapping registers to core: %s\n",core->description)); + + MALI_SUCCESS; +} + +/* Used by external renderunit_create<> function + other places */ +void mali_core_renderunit_unmap_registers(mali_core_renderunit *core) +{ + MALI_DEBUG_PRINT(3, ("Core: renderunit_unmap_registers: Core:%s\n", core->description)); + if (0 == core->registers_mapped) + { + MALI_PRINT_ERROR(("Trying to unmap register-mapping with NULL from core: %s\n", core->description)); + return; + } + _mali_osk_mem_unmapioregion(core->registers_base_addr, core->size, core->registers_mapped); + core->registers_mapped = 0; + _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); +} + +static void mali_core_renderunit_irq_handler_remove(mali_core_renderunit *core) +{ + MALI_DEBUG_PRINT(3, ("Core: renderunit_irq_handler_remove: Core:%s\n", core->description)); + _mali_osk_irq_term(core->irq); +} + +mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr) +{ + mali_core_renderunit * core; + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + if (subsys->number_of_cores <= mali_core_nr) + { + MALI_PRINT_ERROR(("Trying to get illegal mali_core_nr: 0x%x for %s", mali_core_nr, subsys->name)); + return NULL; + } + core = (subsys->mali_core_array)[mali_core_nr]; + MALI_DEBUG_PRINT(6, ("Core: renderunit_get_mali_core_nr: Core:%s\n", core->description)); + MALI_CHECK_CORE(core); + return core; +} + +/* Is used by external function: + subsystem_startup<> */ +_mali_osk_errcode_t mali_core_subsystem_init(mali_core_subsystem* new_subsys) +{ + int i; + + /* These function pointers must have been set on before calling this function */ + if ( + ( NULL == new_subsys->name ) || + ( NULL == new_subsys->start_job ) || + ( NULL == new_subsys->irq_handler_upper_half ) || + ( NULL == new_subsys->irq_handler_bottom_half ) || + ( NULL == new_subsys->get_new_job_from_user ) || + ( NULL == new_subsys->return_job_to_user ) + ) + { + MALI_PRINT_ERROR(("Missing functions in subsystem.")); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + MALI_DEBUG_PRINT(2, ("Core: subsystem_init: %s\n", new_subsys->name)) ; + + /* Catch use-before-initialize/use-after-terminate */ + MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); + + new_subsys->magic_nr = SUBSYSTEM_MAGIC_NR; + + _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_idle_head); /* Idle cores of this type */ + _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_off_head); /* Powered off cores of this type */ + + /* Linked list for each priority of sessions with a job ready for scheduleing */ + for(i=0; i<PRIORITY_LEVELS; ++i) + { + _MALI_OSK_INIT_LIST_HEAD(&new_subsys->awaiting_sessions_head[i]); + } + + /* Linked list of all sessions connected to this coretype */ + _MALI_OSK_INIT_LIST_HEAD(&new_subsys->all_sessions_head); + + MALI_SUCCESS; +} + +#if USING_MMU +void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys) +{ + u32 i; + mali_core_renderunit * core; + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + if ( NULL==core ) break; + core->mmu = mali_memory_core_mmu_lookup(core->mmu_id); + MALI_DEBUG_PRINT(2, ("Attach mmu: 0x%x to core: %s in subsystem: %s\n", core->mmu, core->description, subsys->name)); + } + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); +} +#endif + +/* This will register an IRQ handler, and add the core to the list of available cores for this subsystem. */ +_mali_osk_errcode_t mali_core_subsystem_register_renderunit(mali_core_subsystem* subsys, mali_core_renderunit * core) +{ + mali_core_renderunit ** mali_core_array; + u32 previous_nr; + u32 previous_size; + u32 new_nr; + u32 new_size; + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + + /* If any of these are 0 there is an error */ + if(0 == core->subsystem || + 0 == core->registers_base_addr || + 0 == core->size || + 0 == core->description) + { + MALI_PRINT_ERROR(("Missing fields in the core structure 0x%x 0x%x 0x%x;\n", + core->registers_base_addr, core->size, core->description)); + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + + MALI_DEBUG_PRINT(3, ("Core: subsystem_register_renderunit: %s\n", core->description)); + + MALI_CHECK_NON_NULL( + core->irq = _mali_osk_irq_init( + core->irq_nr, + mali_core_irq_handler_upper_half, + mali_core_irq_handler_bottom_half, + (_mali_osk_irq_trigger_t)subsys->probe_core_irq_trigger, + (_mali_osk_irq_ack_t)subsys->probe_core_irq_acknowledge, + core, + "mali_core_irq_handlers" + ), + _MALI_OSK_ERR_FAULT + ); + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + + /* Update which core number this is */ + core->core_number = subsys->number_of_cores; + + /* Update the array of cores in the subsystem. */ + previous_nr = subsys->number_of_cores; + previous_size = sizeof(mali_core_renderunit*)*previous_nr; + new_nr = previous_nr + 1; + new_size = sizeof(mali_core_renderunit*)*new_nr; + + if (0 != previous_nr) + { + if (NULL == subsys->mali_core_array) + { + MALI_PRINT_ERROR(("Internal error")); + goto exit_function; + } + + mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); + if (NULL == mali_core_array ) + { + MALI_PRINT_ERROR(("Out of mem")); + err = _MALI_OSK_ERR_NOMEM; + goto exit_function; + } + _mali_osk_memcpy(mali_core_array, subsys->mali_core_array, previous_size); + _mali_osk_free( subsys->mali_core_array); + MALI_DEBUG_PRINT(5, ("Success: adding a new core to subsystem array %s\n", core->description) ) ; + } + else + { + mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); + if (NULL == mali_core_array ) + { + MALI_PRINT_ERROR(("Out of mem")); + err = _MALI_OSK_ERR_NOMEM; + goto exit_function; + } + MALI_DEBUG_PRINT(6, ("Success: adding first core to subsystem array %s\n", core->description) ) ; + } + subsys->mali_core_array = mali_core_array; + mali_core_array[previous_nr] = core; + + /* Add the core to the list of available cores on the system */ + _mali_osk_list_add(&(core->list), &(subsys->renderunit_idle_head)); + + /* Update total number of cores */ + subsys->number_of_cores = new_nr; + MALI_DEBUG_PRINT(6, ("Success: mali_core_subsystem_register_renderunit %s\n", core->description)); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_SUCCESS; + +exit_function: + mali_core_renderunit_irq_handler_remove(core); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_ERROR(err); +} + + +/** + * Called by the core when a system info update is needed + * We fill in info about all the core types available + * @param subsys Pointer to the core's @a mali_core_subsystem data structure + * @param info Pointer to system info struct to update + * @return _MALI_OSK_ERR_OK on success, or another _mali_osk_errcode_t error code on failure + */ +_mali_osk_errcode_t mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info) +{ + u32 i; + _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; /* OK if no cores to update info for */ + mali_core_renderunit * core; + _mali_core_info **core_info_nextp; + _mali_core_info * cinfo; + + MALI_DEBUG_PRINT(4, ("mali_core_subsystem_system_info_fill: %s\n", subsys->name) ) ; + + /* check input */ + MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); + + core_info_nextp = &(info->core_info); + cinfo = info->core_info; + + while(NULL!=cinfo) + { + core_info_nextp = &(cinfo->next); + cinfo = cinfo->next; + } + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + if ( NULL==core ) + { + err = _MALI_OSK_ERR_FAULT; + goto early_exit; + } + cinfo = (_mali_core_info *)_mali_osk_calloc(1, sizeof(_mali_core_info)); + if ( NULL==cinfo ) + { + err = _MALI_OSK_ERR_NOMEM; + goto early_exit; + } + cinfo->version = core->core_version; + cinfo->type =subsys->core_type; + cinfo->reg_address = core->registers_base_addr; + cinfo->core_nr = i; + cinfo->next = NULL; + /* Writing this address to the previous' *(&next) ptr */ + *core_info_nextp = cinfo; + /* Setting the next_ptr to point to &this->next_ptr */ + core_info_nextp = &(cinfo->next); + } +early_exit: + if ( _MALI_OSK_ERR_OK != err) MALI_PRINT_ERROR(("Error: In mali_core_subsystem_system_info_fill %d\n", err)); + MALI_DEBUG_CODE( + cinfo = info->core_info; + + MALI_DEBUG_PRINT(3, ("Current list of cores\n")); + while( NULL != cinfo ) + { + MALI_DEBUG_PRINT(3, ("Type: 0x%x\n", cinfo->type)); + MALI_DEBUG_PRINT(3, ("Version: 0x%x\n", cinfo->version)); + MALI_DEBUG_PRINT(3, ("Reg_addr: 0x%x\n", cinfo->reg_address)); + MALI_DEBUG_PRINT(3, ("Core_nr: 0x%x\n", cinfo->core_nr)); + MALI_DEBUG_PRINT(3, ("Flags: 0x%x\n", cinfo->flags)); + MALI_DEBUG_PRINT(3, ("*****\n")); + cinfo = cinfo->next; + } + ); + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_ERROR(err); +} + + +/* Is used by external function: + subsystem_terminate<> */ +void mali_core_subsystem_cleanup(mali_core_subsystem* subsys) +{ + u32 i; + mali_core_renderunit * core; + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + MALI_DEBUG_PRINT(2, ("Core: subsystem_cleanup: %s\n", subsys->name )) ; + + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + +#if USING_MMU + if (NULL != core->mmu) + { + /* the MMU is attached in the load_complete callback, which will never be called if the module fails to load, handle that case */ + mali_memory_core_mmu_unregister_callback(core->mmu, mali_core_subsystem_callback_schedule_wrapper); + } +#endif + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + + mali_core_renderunit_irq_handler_remove(core); + + /* When a process terminates, all cores running jobs from that process is reset and put to idle. + That means that when the module is unloading (this code) we are guaranteed that all cores are idle. + However: if something (we can't think of) is really wrong, a core may give an interrupt during this + unloading, and we may now in the code have a bottom-half-processing pending from the interrupts + we deregistered above. To be sure that the bottom halves do not access the structures after they + are deallocated we flush the bottom-halves processing here, before the deallocation. */ + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + +#if USING_MALI_PMM + /* Only reset when we are using PMM and the core is not off */ +#if MALI_PMM_NO_PMU + /* We need to reset when there is no PMU - but this will + * cause the register read/write functions to report an + * error (hence the if to check for CORE_OFF below) we + * change state to allow the reset to happen. + */ + core->state = CORE_IDLE; +#endif + if( core->state != CORE_OFF ) + { + subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); + } +#else + /* Always reset the core */ + subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); +#endif + + mali_core_renderunit_unmap_registers(core); + + _mali_osk_list_delinit(&core->list); + + mali_core_renderunit_term(core); + + subsys->renderunit_delete(core); + } + + mali_core_subsystem_cleanup_all_renderunits(subsys); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_DEBUG_PRINT(6, ("SUCCESS: mali_core_subsystem_cleanup: %s\n", subsys->name )) ; +} + +_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores) +{ + mali_core_subsystem * subsystem; + + subsystem = session->subsystem; + if ( NULL != number_of_cores ) + { + *number_of_cores = subsystem->number_of_cores; + } + + MALI_DEBUG_PRINT(4, ("Core: ioctl_number_of_cores_get: %s: %u\n", subsystem->name, *number_of_cores) ) ; + + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data) +{ + mali_core_subsystem * subsystem; + _mali_osk_errcode_t err; + + /* need the subsystem to run callback function */ + subsystem = session->subsystem; + MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); + err = subsystem->get_new_job_from_user(session, job_data); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); + + MALI_ERROR(err); +} + + +/* We return the version number to the first core in this subsystem */ +_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version) +{ + mali_core_subsystem * subsystem; + mali_core_renderunit * core0; + u32 nr_return; + + subsystem = session->subsystem; + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); + + core0 = mali_core_renderunit_get_mali_core_nr(subsystem, 0); + + if( NULL == core0 ) + { + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + nr_return = core0->core_version; + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); + + MALI_DEBUG_PRINT(4, ("Core: ioctl_core_version_get: %s: %u\n", subsystem->name, nr_return )) ; + + *version = nr_return; + + MALI_SUCCESS; +} + +void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id) +{ + find_and_abort(session, id); +} + +static mali_bool job_should_be_aborted(mali_core_job *job, u32 abort_id) +{ + if ( job->abort_id == abort_id ) return MALI_TRUE; + else return MALI_FALSE; +} + +static void find_and_abort(mali_core_session* session, u32 abort_id) +{ + mali_core_subsystem * subsystem; + mali_core_renderunit *core; + mali_core_renderunit *tmp; + mali_core_job *job; + + subsystem = session->subsystem; + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); + + job = session->job_waiting_to_run; + if ( (job!=NULL) && job_should_be_aborted (job, abort_id) ) + { + MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, from the waiting_to_run slot.\n", subsystem->name, abort_id )); + session->job_waiting_to_run = NULL; + _mali_osk_list_delinit(&(session->awaiting_sessions_list)); + subsystem->awaiting_sessions_sum_all_priorities--; + subsystem->return_job_to_user( job , JOB_STATUS_END_ABORT); + } + + _MALI_OSK_LIST_FOREACHENTRY( core, tmp, &session->renderunits_working_head, mali_core_renderunit, list ) + { + job = core->current_job; + if ( (job!=NULL) && (job_should_be_aborted (job, abort_id) ) ) + { + MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, which is currently running on mali.\n", subsystem->name, abort_id )); + if ( core->state==CORE_IDLE ) + { + MALI_PRINT_ERROR(("Aborting core with running job which is idle. Must be something very wrong.")); + goto end_bug; + } + mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_ABORT); + } + } +end_bug: + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); +} + + +_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void *argument) +{ + mali_core_subsystem * subsystem; + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + + /* need the subsystem to run callback function */ + subsystem = session->subsystem; + MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); + if ( NULL != subsystem->suspend_response) + { + MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE start\n")); + err = subsystem->suspend_response(session, argument); + MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE end\n")); + } + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); + + return err; +} + + +/* Is used by internal function: + mali_core_subsystem_cleanup<>s */ +/* All cores should be removed before calling this function +Must hold subsystem_mutex before entering this function */ +static void mali_core_subsystem_cleanup_all_renderunits(mali_core_subsystem* subsys) +{ + int i; + _mali_osk_free(subsys->mali_core_array); + subsys->number_of_cores = 0; + + MALI_DEBUG_PRINT(5, ("Core: subsystem_cleanup_all_renderunits: %s\n", subsys->name) ) ; + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + + if ( ! _mali_osk_list_empty(&(subsys->renderunit_idle_head))) + { + MALI_PRINT_ERROR(("List renderunit_list_idle should be empty.")); + _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_idle_head)) ; + } + + if ( ! _mali_osk_list_empty(&(subsys->renderunit_off_head))) + { + MALI_PRINT_ERROR(("List renderunit_list_off should be empty.")); + _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_off_head)) ; + } + + for(i=0; i<PRIORITY_LEVELS; ++i) + { + if ( ! _mali_osk_list_empty(&(subsys->awaiting_sessions_head[i]))) + { + MALI_PRINT_ERROR(("List awaiting_sessions_linkedlist should be empty.")); + _MALI_OSK_INIT_LIST_HEAD(&(subsys->awaiting_sessions_head[i])) ; + subsys->awaiting_sessions_sum_all_priorities = 0; + } + } + + if ( ! _mali_osk_list_empty(&(subsys->all_sessions_head))) + { + MALI_PRINT_ERROR(("List all_sessions_linkedlist should be empty.")); + _MALI_OSK_INIT_LIST_HEAD(&(subsys->all_sessions_head)) ; + } +} + +/* Is used by internal functions: + mali_core_irq_handler_bottom_half<>; + mali_core_subsystem_schedule<>; */ +/* Will release the core.*/ +/* Must hold subsystem_mutex before entering this function */ +static void mali_core_subsystem_move_core_set_idle(mali_core_renderunit *core) +{ + mali_core_subsystem *subsystem; +#if USING_MALI_PMM + mali_core_status oldstatus; +#endif + subsystem = core->subsystem; + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + MALI_CHECK_CORE(core); + MALI_CHECK_SUBSYSTEM(subsystem); + + _mali_osk_timer_del(core->timer); + _mali_osk_timer_del(core->timer_hang_detection); + + MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_idle: %s\n", core->description) ) ; + + core->current_job = NULL ; + +#if USING_MALI_PMM + + oldstatus = core->state; + + if( core->pend_power_down ) + { + core->state = CORE_OFF ; + _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); + /* Done the move from the active queues, so the pending power down can be done */ + core->pend_power_down = MALI_FALSE; + malipmm_core_power_down_okay( core->pmm_id ); + } + else + { + core->state = CORE_IDLE ; + _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); + } + + if( CORE_OFF != oldstatus ) + { + /* Message that this core is now idle or in fact off */ + _mali_uk_pmm_message_s event = { + NULL, + MALI_PMM_EVENT_JOB_FINISHED, + 0 }; + event.data = core->pmm_id; + _mali_ukk_pmm_event_message( &event ); +#if USING_MMU + /* Only free the reference when entering idle state from + * anything other than power off + */ + mali_memory_core_mmu_release_address_space_reference(core->mmu); +#endif /* USING_MMU */ + } + + +#else /* !USING_MALI_PMM */ + + core->state = CORE_IDLE ; + _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); + +#if USING_MMU + mali_memory_core_mmu_release_address_space_reference(core->mmu); +#endif + +#endif /* USING_MALI_PMM */ +} + +/* Must hold subsystem_mutex before entering this function */ +static void mali_core_subsystem_move_set_working(mali_core_renderunit *core, mali_core_job *job) +{ + mali_core_subsystem *subsystem; + mali_core_session *session; + + session = job->session; + subsystem = core->subsystem; + + MALI_CHECK_CORE(core); + MALI_CHECK_JOB(job); + MALI_CHECK_SUBSYSTEM(subsystem); + + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + MALI_DEBUG_PRINT(5, ("Core: subsystem_move_set_working: %s\n", core->description) ) ; + + core->current_job = job ; + core->state = CORE_WORKING ; + job->start_time_jiffies = _mali_osk_time_tickcount(); + _mali_osk_list_move( &core->list, &session->renderunits_working_head ); + +} + +#if USING_MALI_PMM + +/* Must hold subsystem_mutex before entering this function */ +static void mali_core_subsystem_move_core_set_off(mali_core_renderunit *core) +{ + mali_core_subsystem *subsystem; + subsystem = core->subsystem; + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + MALI_CHECK_CORE(core); + MALI_CHECK_SUBSYSTEM(subsystem); + + /* Cores must be idle before powering off */ + MALI_DEBUG_ASSERT(core->state == CORE_IDLE); + + MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_off: %s\n", core->description) ) ; + + core->current_job = NULL ; + core->state = CORE_OFF ; + _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); +} + +#endif /* USING_MALI_PMM */ + +/* Is used by internal function: + mali_core_subsystem_schedule<>; */ +/* Returns the job with the highest priority for the subsystem. NULL if none*/ +/* Must hold subsystem_mutex before entering this function */ +static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem) +{ + int i; + + MALI_CHECK_SUBSYSTEM(subsystem); + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + if ( 0 == subsystem->awaiting_sessions_sum_all_priorities ) + { + MALI_DEBUG_PRINT(5, ("Core: subsystem_get_waiting_job: No awaiting session found\n")); + return NULL; + } + + for( i=0; i<PRIORITY_LEVELS ; ++i) + { + if (!_mali_osk_list_empty(&subsystem->awaiting_sessions_head[i])) + { + return _MALI_OSK_LIST_ENTRY(subsystem->awaiting_sessions_head[i].next, mali_core_session, awaiting_sessions_list); + } + } + + return NULL; +} + +static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session) +{ + mali_core_job *job; + MALI_CHECK_SUBSYSTEM(subsystem); + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + _mali_osk_list_delinit(&session->awaiting_sessions_list); + subsystem->awaiting_sessions_sum_all_priorities--; + job = session->job_waiting_to_run; + session->job_waiting_to_run = NULL; + MALI_CHECK_JOB(job); + return job; +} + +/* Is used by internal functions: + mali_core_subsystem_schedule<> */ +/* This will start the job on the core. It will also release the core if it did not start.*/ +/* Must hold subsystem_mutex before entering this function */ +static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core) +{ + mali_core_session *session; + mali_core_subsystem *subsystem; + _mali_osk_errcode_t err; + session = job->session; + subsystem = core->subsystem; + + MALI_CHECK_CORE(core); + MALI_CHECK_JOB(job); + MALI_CHECK_SUBSYSTEM(subsystem); + MALI_CHECK_SESSION(session); + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + MALI_DEBUG_PRINT(4, ("Core: job_start_on_core: job=0x%x, session=0x%x, core=%s\n", job, session, core->description)); + + MALI_DEBUG_ASSERT(NULL == core->current_job) ; + MALI_DEBUG_ASSERT(CORE_IDLE == core->state ); + + mali_core_subsystem_move_set_working(core, job); + +#if defined USING_MALI400_L2_CACHE + /* Invalidate the L2 cache */ + if (_MALI_OSK_ERR_OK != mali_kernel_l2_cache_invalidate_all() ) + { + MALI_DEBUG_PRINT(4, ("Core: Clear of L2 failed, return job. System may not be usable for some reason.\n")); + mali_core_subsystem_move_core_set_idle(core); + subsystem->return_job_to_user(job,JOB_STATUS_END_SYSTEM_UNUSABLE ); + return; + } +#endif + + /* Tries to start job on the core. Returns MALI_FALSE if the job could not be started */ + err = subsystem->start_job(job, core); + +#if MALI_GPU_UTILIZATION + mali_utilization_core_start(); +#endif + + if ( _MALI_OSK_ERR_OK != err ) + { + /* This will happen only if there is something in the job object + which make it inpossible to start. Like if it require illegal memory.*/ + MALI_DEBUG_PRINT(4, ("Core: start_job failed, return job and putting core back into idle list\n")); + mali_core_subsystem_move_core_set_idle(core); + subsystem->return_job_to_user(job,JOB_STATUS_END_ILLEGAL_JOB ); + } + else + { + u32 delay = _mali_osk_time_mstoticks(job->watchdog_msecs)+1; + job->watchdog_jiffies = _mali_osk_time_tickcount() + delay; + if (mali_benchmark) + { + _mali_osk_timer_add(core->timer, 1); + } + else + { + _mali_osk_timer_add(core->timer, delay); + } + } +} + +#if USING_MMU +static void mali_core_subsystem_callback_schedule_wrapper(void* sub) +{ + mali_core_subsystem * subsystem; + subsystem = (mali_core_subsystem *)sub; + MALI_DEBUG_PRINT(3, ("MMU: Is schedulling subsystem: %s\n", subsystem->name)); + mali_core_subsystem_schedule(subsystem); +} +#endif + +/* Is used by internal function: + mali_core_irq_handler_bottom_half + mali_core_session_add_job +*/ +/* Must hold subsystem_mutex before entering this function */ +static void mali_core_subsystem_schedule(mali_core_subsystem * subsystem) +{ + mali_core_renderunit *core, *tmp; + mali_core_session *session; + mali_core_job *job; + + MALI_DEBUG_PRINT(5, ("Core: subsystem_schedule: %s\n", subsystem->name )) ; + + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + /* First check that there are sessions with jobs waiting to run */ + if ( 0 == subsystem->awaiting_sessions_sum_all_priorities) + { + MALI_DEBUG_PRINT(6, ("Core: No jobs available for %s\n", subsystem->name) ) ; + return; + } + + /* Returns the session with the highest priority job for the subsystem. NULL if none*/ + session = mali_core_subsystem_get_waiting_session(subsystem); + + if (NULL == session) + { + MALI_DEBUG_PRINT(6, ("Core: Schedule: No runnable job found\n")); + return; + } + + _MALI_OSK_LIST_FOREACHENTRY(core, tmp, &subsystem->renderunit_idle_head, mali_core_renderunit, list) + { +#if USING_MMU + int err = mali_memory_core_mmu_activate_page_table(core->mmu, session->mmu_session, mali_core_subsystem_callback_schedule_wrapper, subsystem); + if (0 == err) + { + /* core points to a core where the MMU page table activation succeeded */ +#endif + /* This will remove the job from queue system */ + job = mali_core_subsystem_release_session_get_job(subsystem, session); + MALI_DEBUG_ASSERT_POINTER(job); + + MALI_DEBUG_PRINT(6, ("Core: Schedule: Got a job 0x%x\n", job)); + +#if USING_MALI_PMM + { + /* Message that there is a job scheduled to run + * NOTE: mali_core_job_start_on_core() can fail to start + * the job for several reasons, but it will move the core + * back to idle which will create the FINISHED message + * so we can still say that the job is SCHEDULED + */ + _mali_uk_pmm_message_s event = { + NULL, + MALI_PMM_EVENT_JOB_SCHEDULED, + 0 }; + event.data = core->pmm_id; + _mali_ukk_pmm_event_message( &event ); + } +#endif + /* This will {remove core from freelist AND start the job on the core}*/ + mali_core_job_start_on_core(job, core); + + MALI_DEBUG_PRINT(6, ("Core: Schedule: Job started, done\n")); + return; +#if USING_MMU + } +#endif + } + MALI_DEBUG_PRINT(6, ("Core: Schedule: Could not activate MMU. Scheduelling postponed to MMU, checking next.\n")); + +#if USING_MALI_PMM + { + /* Message that there are jobs to run */ + _mali_uk_pmm_message_s event = { + NULL, + MALI_PMM_EVENT_JOB_QUEUED, + 0 }; + if( subsystem->core_type == _MALI_GP2 || subsystem->core_type == _MALI_400_GP ) + { + event.data = MALI_PMM_CORE_GP; + } + else + { + /* Check the PP is supported by the PMM */ + MALI_DEBUG_ASSERT( subsystem->core_type == _MALI_200 || subsystem->core_type == _MALI_400_PP ); + /* We state that all PP cores are scheduled to inform the PMM + * that it may need to power something up! + */ + event.data = MALI_PMM_CORE_PP_ALL; + } + _mali_ukk_pmm_event_message( &event ); + } +#endif /* USING_MALI_PMM */ + +} + +/* Is used by external function: + session_begin<> */ +void mali_core_session_begin(mali_core_session * session) +{ + mali_core_subsystem * subsystem; + + subsystem = session->subsystem; + if ( NULL == subsystem ) + { + MALI_PRINT_ERROR(("Missing data in struct\n")); + return; + } + MALI_DEBUG_PRINT(2, ("Core: session_begin: for %s\n", session->subsystem->name )) ; + + session->magic_nr = SESSION_MAGIC_NR; + + _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); + + session->job_waiting_to_run = NULL; + _MALI_OSK_INIT_LIST_HEAD(&session->awaiting_sessions_list); + _MALI_OSK_INIT_LIST_HEAD(&session->all_sessions_list); + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); + _mali_osk_list_add(&session->all_sessions_list, &session->subsystem->all_sessions_head); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); + + MALI_DEBUG_PRINT(5, ("Core: session_begin: for %s DONE\n", session->subsystem->name) ) ; +} + +#if USING_MMU +static void mali_core_renderunit_stop_bus(mali_core_renderunit* core) +{ + core->subsystem->stop_bus(core); +} +#endif + +void mali_core_session_close(mali_core_session * session) +{ + mali_core_subsystem * subsystem; + mali_core_renderunit *core; + + subsystem = session->subsystem; + MALI_DEBUG_ASSERT_POINTER(subsystem); + + MALI_DEBUG_PRINT(2, ("Core: session_close: for %s\n", session->subsystem->name) ) ; + + /* We must grab subsystem mutex since the list this session belongs to + is owned by the subsystem */ + MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); + + /* Return the potensial waiting job to user */ + if ( session->job_waiting_to_run ) + { + subsystem->return_job_to_user( session->job_waiting_to_run, JOB_STATUS_END_SHUTDOWN ); + session->job_waiting_to_run = NULL; + _mali_osk_list_delinit(&(session->awaiting_sessions_list)); + subsystem->awaiting_sessions_sum_all_priorities--; + } + + /* Kill active cores working for this session - freeing their jobs + Since the handling of one core also could stop jobs from another core, there is a while loop */ + while ( ! _mali_osk_list_empty(&session->renderunits_working_head) ) + { + core = _MALI_OSK_LIST_ENTRY(session->renderunits_working_head.next, mali_core_renderunit, list); + MALI_DEBUG_PRINT(3, ("Core: session_close: Core was working: %s\n", core->description )) ; + mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_SHUTDOWN ); + break; + } + _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); /* Not necessary - we will _mali_osk_free session*/ + + /* Remove this session from the global sessionlist */ + _mali_osk_list_delinit(&session->all_sessions_list); + + MALI_DEBUG_PRINT(5, ("Core: session_close: for %s FINISHED\n", session->subsystem->name )) ; + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); +} + +/* Must hold subsystem_mutex before entering this function */ +_mali_osk_errcode_t mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return) +{ + mali_core_subsystem * subsystem; + + job->magic_nr = JOB_MAGIC_NR; + MALI_CHECK_SESSION(session); + + subsystem = session->subsystem; + MALI_CHECK_SUBSYSTEM(subsystem); + MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); + + MALI_DEBUG_PRINT(5, ("Core: session_add_job: for %s\n", subsystem->name )) ; + + /* Setting the default value; No job to return */ + MALI_DEBUG_ASSERT_POINTER(job_return); + *job_return = NULL; + + if ( NULL != session->job_waiting_to_run) + { + MALI_DEBUG_PRINT(5, ("The session already had a job waiting\n")) ; + /* Checing if the new job has a higher priority than the one that was pending.*/ + if ( job_has_higher_priority(job,session->job_waiting_to_run)) + { + /* Remove this session from current priority */ + _mali_osk_list_del( &(session->awaiting_sessions_list)); + subsystem->awaiting_sessions_sum_all_priorities--; + /* Returning the previous waiting job through the input double pointer*/ + *job_return = session->job_waiting_to_run; + } + else + { + MALI_PRINT_ERROR(("Illegal internal state.")); + /* There was a job waiting in this session, and the priority of this job + we try to add was NOT higher. Return -1 indicated new job NOT enqueued.*/ + /* We check prior to calling this function that we are not in this state.*/ + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + } + /* Continue to add the new job as the next job from this session */ + MALI_DEBUG_PRINT(6, ("Core: session_add_job job=0x%x\n", job)); + + /* Adding this session to the subsystem list of sessions with pending job, with priority */ + session->job_waiting_to_run = job; + + _mali_osk_list_addtail( &(session->awaiting_sessions_list), &(subsystem->awaiting_sessions_head[job->priority])); + subsystem->awaiting_sessions_sum_all_priorities++; + + mali_core_subsystem_schedule(subsystem); + + MALI_DEBUG_PRINT(6, ("Core: session_add_job: for %s FINISHED\n", session->subsystem->name )) ; + + MALI_SUCCESS; +} + +static void mali_core_job_set_run_time(mali_core_job * job) +{ + u32 jiffies_used; + jiffies_used = _mali_osk_time_tickcount() - job->start_time_jiffies; + if ( jiffies_used > JOB_MAX_JIFFIES ) + { + MALI_PRINT_ERROR(("Job used too many jiffies: %d\n", jiffies_used )); + jiffies_used = 0; + } + job->render_time_msecs = _mali_osk_time_tickstoms(jiffies_used); +} + +static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status) +{ + mali_core_job * job; + mali_core_subsystem * subsystem; + mali_bool already_in_detach_function; + + job = core->current_job; + subsystem = core->subsystem; + MALI_DEBUG_ASSERT(CORE_IDLE != core->state); + + /* The reset_core() called some lines below might call this detach + * funtion again. To protect the core object from being modified by + * recursive calls, the in_detach_function would track if it is an recursive call + */ + already_in_detach_function = core->in_detach_function; + + if ( MALI_FALSE == already_in_detach_function ) + { + core->in_detach_function = MALI_TRUE; + if ( NULL != job ) + { + mali_core_job_set_run_time(job); + core->current_job = NULL; + } + } + + if (JOB_STATUS_END_SEG_FAULT == end_status) + { + subsystem->reset_core( core, MALI_CORE_RESET_STYLE_HARD ); + } + else + { + subsystem->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); + } + + if ( MALI_FALSE == already_in_detach_function ) + { + if ( CORE_IDLE != core->state ) + { + #if MALI_GPU_UTILIZATION + mali_utilization_core_end(); + #endif + mali_core_subsystem_move_core_set_idle(core); + } + + core->in_detach_function = MALI_FALSE; + + if ( SUBSYSTEM_RESCHEDULE == reschedule ) + { + mali_core_subsystem_schedule(subsystem); + } + if ( NULL != job ) + { + core->subsystem->return_job_to_user(job, end_status); + } + } +} + +#if USING_MMU +/* This function intentionally does not release the semaphore. You must run + stop_bus_for_all_cores(), reset_all_cores_on_mmu() and continue_job_handling() + after calling this function, and then call unlock_subsystem() to release the + semaphore. */ + +static void lock_subsystem(struct mali_core_subsystem * subsys) +{ + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); +} + +/* You must run lock_subsystem() before entering this function, to ensure that + the subsystem mutex is held. + Later, unlock_subsystem() can be called to release the mutex. + + This function only stops cores behind the given MMU, unless "mmu" is NULL, in + which case all cores are stopped. +*/ +static void stop_bus_for_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) +{ + u32 i; + + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + MALI_DEBUG_PRINT(2,("Handling: bus stop %s\n", subsys->name )); + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + mali_core_renderunit * core; + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + + /* We stop only cores behind the given MMU, unless MMU is NULL */ + if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; + + if ( CORE_IDLE != core->state ) + { + MALI_DEBUG_PRINT(4, ("Stopping bus on core %s\n", core->description)); + mali_core_renderunit_stop_bus(core); + core->error_recovery = MALI_TRUE; + } + else + { + MALI_DEBUG_PRINT(4,("Core: not active %s\n", core->description )); + } + } + /* Mutex is still being held, to prevent things to happen while we do cleanup */ + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); +} + +/* You must run lock_subsystem() before entering this function, to ensure that + the subsystem mutex is held. + Later, unlock_subsystem() can be called to release the mutex. + + This function only resets cores behind the given MMU, unless "mmu" is NULL, in + which case all cores are reset. +*/ +static void reset_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) +{ + u32 i; + + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + MALI_DEBUG_PRINT(3, ("Handling: reset cores from mmu: 0x%x on %s\n", mmu, subsys->name )); + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + mali_core_renderunit * core; + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + + /* We reset only cores behind the given MMU, unless MMU is NULL */ + if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; + + if ( CORE_IDLE != core->state ) + { + MALI_DEBUG_PRINT(4, ("Abort and reset core: %s\n", core->description )); + mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_WAIT, JOB_STATUS_END_SEG_FAULT); + } + else + { + MALI_DEBUG_PRINT(4, ("Core: not active %s\n", core->description )); + } + } + MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); +} + +/* You must run lock_subsystem() before entering this function, to ensure that + the subsystem mutex is held. + Later, unlock_subsystem() can be called to release the mutex. */ +static void continue_job_handling(struct mali_core_subsystem * subsys) +{ + u32 i, j; + + MALI_DEBUG_PRINT(3, ("Handling: Continue: %s\n", subsys->name )); + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + + + for(i=0 ; i < subsys->number_of_cores ; ++i) + { + mali_core_renderunit * core; + core = mali_core_renderunit_get_mali_core_nr(subsys,i); + core->error_recovery = MALI_FALSE; + } + + i = subsys->number_of_cores; + j = subsys->awaiting_sessions_sum_all_priorities; + + /* Schedule MIN(nr_waiting_jobs , number of cores) times */ + while( i-- && j--) + { + mali_core_subsystem_schedule(subsys); + } + MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); +} + +/* Unlock the subsystem. */ +static void unlock_subsystem(struct mali_core_subsystem * subsys) +{ + MALI_ASSERT_MUTEX_IS_GRABBED(subsys); + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); +} + +void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data) +{ + void * mmu; + mmu = (void*) data; + + switch(message) + { + case MMU_KILL_STEP0_LOCK_SUBSYSTEM: + break; + case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: + stop_bus_for_all_cores_on_mmu(subsys, mmu); + break; + case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: + reset_all_cores_on_mmu(subsys, mmu ); + break; + case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: + continue_job_handling(subsys); + break; + case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: + break; + + default: + MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); + break; + } +} +#endif /* USING_MMU */ + +void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs) +{ + if (watchdog_msecs == 0) job->watchdog_msecs = mali_max_job_runtime; /* use the default */ + else if (watchdog_msecs > WATCHDOG_MSECS_MAX) job->watchdog_msecs = WATCHDOG_MSECS_MAX; /* no larger than max */ + else if (watchdog_msecs < WATCHDOG_MSECS_MIN) job->watchdog_msecs = WATCHDOG_MSECS_MIN; /* not below min */ + else job->watchdog_msecs = watchdog_msecs; +} + +u32 mali_core_hang_check_timeout_get(void) +{ + /* check the value. The user might have set the value outside the allowed range */ + if (mali_hang_check_interval > HANG_CHECK_MSECS_MAX) mali_hang_check_interval = HANG_CHECK_MSECS_MAX; /* cap to max */ + else if (mali_hang_check_interval < HANG_CHECK_MSECS_MIN) mali_hang_check_interval = HANG_CHECK_MSECS_MIN; /* cap to min */ + + /* return the active value */ + return mali_hang_check_interval; +} + +static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data) +{ + mali_core_renderunit *core; + u32 has_pending_irq; + + core = (mali_core_renderunit * )data; + + if ( (NULL == core) || + (NULL == core->subsystem) || + (NULL == core->subsystem->irq_handler_upper_half) ) + { + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + MALI_CHECK_CORE(core); + MALI_CHECK_SUBSYSTEM(core->subsystem); + + has_pending_irq = core->subsystem->irq_handler_upper_half(core); + + if ( has_pending_irq ) + { + _mali_osk_irq_schedulework( core->irq ) ; + MALI_SUCCESS; + } + + if (mali_benchmark) MALI_SUCCESS; + + MALI_ERROR(_MALI_OSK_ERR_FAULT); +} + +static void mali_core_irq_handler_bottom_half ( void *data ) +{ + mali_core_renderunit *core; + mali_core_subsystem* subsystem; + + mali_subsystem_job_end_code job_status; + + core = (mali_core_renderunit * )data; + + MALI_CHECK_CORE(core); + subsystem = core->subsystem; + MALI_CHECK_SUBSYSTEM(subsystem); + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); + if ( CORE_IDLE == core->state ) goto end_function; + + MALI_DEBUG_PRINT(5, ("IRQ: handling irq from core %s\n", core->description )) ; + + _mali_osk_cache_flushall(); + + /* This function must also update the job status flag */ + job_status = subsystem->irq_handler_bottom_half( core ); + + /* Retval is nonzero if the job is finished. */ + if ( JOB_STATUS_CONTINUE_RUN != job_status ) + { + mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, job_status); + } + else + { + switch ( core->state ) + { + case CORE_WATCHDOG_TIMEOUT: + MALI_DEBUG_PRINT(2, ("Watchdog SW Timeout of job from core: %s\n", core->description )); + mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_TIMEOUT_SW ); + break; + + case CORE_POLL: + MALI_DEBUG_PRINT(5, ("Poll core: %s\n", core->description )) ; + core->state = CORE_WORKING; + _mali_osk_timer_add( core->timer, 1); + break; + + default: + MALI_DEBUG_PRINT(4, ("IRQ: The job on the core continue to run: %s\n", core->description )) ; + break; + } + } +end_function: + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); +} + +void subsystem_flush_mapped_mem_cache(void) +{ + _mali_osk_cache_flushall(); + _mali_osk_mem_barrier(); +} + +#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_core_renderunit * core = NULL; + + MALI_CHECK_SUBSYSTEM(subsys); + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + + /* It is possible that this signal funciton can be called during a driver exit, + * and so the requested core may now be destroyed. (This is due to us not having + * the subsys lock before signalling power down). + * mali_core_renderunit_get_mali_core_nr() will report a Mali ERR because + * the core number is out of range (which is a valid error in other cases). + * So instead we check here (now that we have the subsys lock) and let the + * caller cope with the core get failure and check that the core has + * been unregistered in the PMM as part of its destruction. + */ + if ( subsys->number_of_cores > mali_core_nr ) + { + core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); + } + + if ( NULL == core ) + { + /* Couldn't find the core */ + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_DEBUG_PRINT( 5, ("Core: Failed to find core to power down\n") ); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + else if ( core->state != CORE_IDLE ) + { + /* When powering down we either set a pending power down flag here so we + * can power down cleanly after the job completes or we don't set the + * flag if we have been asked to only do a power down right now + * In either case, return that the core is busy + */ + if ( !immediate_only ) core->pend_power_down = MALI_TRUE; + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_DEBUG_PRINT( 5, ("Core: No idle core to power down\n") ); + MALI_ERROR(_MALI_OSK_ERR_BUSY); + } + + /* Shouldn't have a pending power down flag set */ + MALI_DEBUG_ASSERT( !core->pend_power_down ); + + /* Move core to off queue */ + mali_core_subsystem_move_core_set_off(core); + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only) +{ + mali_core_renderunit * core; + + MALI_CHECK_SUBSYSTEM(subsys); + MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); + + core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); + + if( core == NULL ) + { + /* Couldn't find the core */ + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_DEBUG_PRINT( 5, ("Core: Failed to find core to power up\n") ); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + else if( core->state != CORE_OFF ) + { + /* This will usually happen because we are trying to cancel a pending power down */ + core->pend_power_down = MALI_FALSE; + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + MALI_DEBUG_PRINT( 5, ("Core: No powered off core to power up (cancelled power down?)\n") ); + MALI_ERROR(_MALI_OSK_ERR_BUSY); + } + + /* Shouldn't have a pending power down set */ + MALI_DEBUG_ASSERT( !core->pend_power_down ); + + /* Move core to idle queue */ + mali_core_subsystem_move_core_set_idle(core); + + if( !queue_only ) + { + /* Reset MMU & core - core must be idle to allow this */ +#if USING_MMU + if ( NULL!=core->mmu ) + { +#if defined(USING_MALI200) + if (core->pmm_id != MALI_PMM_CORE_PP0) + { +#endif + mali_kernel_mmu_reset(core->mmu); +#if defined(USING_MALI200) + } +#endif + + } +#endif /* USING_MMU */ + subsys->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); + } + + /* Need to schedule work to start on this core */ + mali_core_subsystem_schedule(subsys); + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); + + MALI_SUCCESS; +} + +#endif /* USING_MALI_PMM */ + +#if MALI_STATE_TRACKING +void mali_core_renderunit_dump_state(mali_core_subsystem* subsystem) +{ + u32 i; + mali_core_renderunit *core; + mali_core_renderunit *tmp_core; + + mali_core_session* session; + mali_core_session* tmp_session; + + MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); + + MALI_PRINT(("Subsystem;\n")); + MALI_PRINT((" Name: %s\n", subsystem->name)); + + for (i = 0; i < subsystem->number_of_cores; i++) + { + MALI_PRINT((" Core: #%u\n", subsystem->mali_core_array[i]->core_number)); + MALI_PRINT((" Description: %s\n", subsystem->mali_core_array[i]->description)); + switch(subsystem->mali_core_array[i]->state) + { + case CORE_IDLE: + MALI_PRINT((" State: CORE_IDLE\n")); + break; + case CORE_WORKING: + MALI_PRINT((" State: CORE_WORKING\n")); + break; + case CORE_WATCHDOG_TIMEOUT: + MALI_PRINT((" State: CORE_WATCHDOG_TIMEOUT\n")); + break; + case CORE_POLL: + MALI_PRINT((" State: CORE_POLL\n")); + break; + case CORE_HANG_CHECK_TIMEOUT: + MALI_PRINT((" State: CORE_HANG_CHECK_TIMEOUT\n")); + break; + case CORE_OFF: + MALI_PRINT((" State: CORE_OFF\n")); + break; + default: + MALI_PRINT((" State: Unknown (0x%X)\n", subsystem->mali_core_array[i]->state)); + break; + } + MALI_PRINT((" Current job: 0x%x\n", (u32)(subsystem->mali_core_array[i]->current_job))); + MALI_PRINT((" Core version: 0x%x\n", subsystem->mali_core_array[i]->core_version)); +#if USING_MALI_PMM + MALI_PRINT((" PMM id: 0x%x\n", subsystem->mali_core_array[i]->pmm_id)); + MALI_PRINT((" Power down requested: %s\n", subsystem->mali_core_array[i]->pend_power_down ? "TRUE" : "FALSE")); +#endif + } + + MALI_PRINT((" Cores on idle list:\n")); + _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_idle_head, mali_core_renderunit, list) + { + MALI_PRINT((" Core #%u\n", core->core_number)); + } + + MALI_PRINT((" Cores on off list:\n")); + _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_off_head, mali_core_renderunit, list) + { + MALI_PRINT((" Core #%u\n", core->core_number)); + } + + MALI_PRINT((" Connected sessions:\n")); + _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->all_sessions_head, mali_core_session, all_sessions_list) + { + MALI_PRINT((" Session 0x%X:\n", (u32)session)); + MALI_PRINT((" Waiting job: 0x%X\n", (u32)session->job_waiting_to_run)); + MALI_PRINT((" Notification queue: %s\n", _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY")); + } + + MALI_PRINT((" Waiting sessions sum all priorities: %u\n", subsystem->awaiting_sessions_sum_all_priorities)); + for (i = 0; i < PRIORITY_LEVELS; i++) + { + MALI_PRINT((" Waiting sessions with priority %u:\n", i)); + _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->awaiting_sessions_head[i], mali_core_session, awaiting_sessions_list) + { + MALI_PRINT((" Session 0x%X:\n", (u32)session)); + MALI_PRINT((" Waiting job: 0x%X\n", (u32)session->job_waiting_to_run)); + MALI_PRINT((" Notification queue: %s\n", _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY")); + } + } + + MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); +} +#endif |