summaryrefslogtreecommitdiff
path: root/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.c
diff options
context:
space:
mode:
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.c2032
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