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