void mali_soft_job_system_destroy(struct mali_soft_job_system *system) { MALI_DEBUG_ASSERT_POINTER(system); /* All jobs should be free at this point. */ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&(system->jobs_used))); if (NULL != system) { if (NULL != system->lock) { _mali_osk_spinlock_irq_term(system->lock); } _mali_osk_free(system); } }
/* Group and scheduler must be locked when entering this function. Both will be unlocked before * exiting. */ static void mali_gp_scheduler_schedule_internal_and_unlock(void) { struct mali_gp_job *job = NULL; MALI_DEBUG_ASSERT_LOCK_HELD(slot.group->lock); MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state || (_mali_osk_list_empty(&job_queue) && _mali_osk_list_empty(&job_queue_high))) { mali_gp_scheduler_unlock(); mali_group_unlock(slot.group); MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0)); #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) trace_gpu_sched_switch(mali_gp_get_hw_core_desc(group->gp_core), sched_clock(), 0, 0, 0); #endif return; /* Nothing to do, so early out */ } /* Get next job in queue */ if (!_mali_osk_list_empty(&job_queue_high)) { job = _MALI_OSK_LIST_ENTRY(job_queue_high.next, struct mali_gp_job, list); } else {
void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) { memory_engine * engine = (memory_engine*)mem_engine; mali_physical_memory_allocation * active_allocation_tracker; MALI_DEBUG_ASSERT_POINTER(engine); MALI_DEBUG_ASSERT_POINTER(descriptor); /* Determine whether we need to remove this from a tracking list */ if ( ! _mali_osk_list_empty( &descriptor->list ) ) { _mali_osk_list_del( &descriptor->list ); /* Clear the list for debug mode, catch use-after-free */ MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; ) }
u32 mali_pp_scheduler_dump_state(char *buf, u32 size) { int n = 0; int i; n += _mali_osk_snprintf(buf + n, size - n, "PP:\n"); n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); n += _mali_osk_snprintf(buf + n, size - n, "\n"); for (i = 0; i < num_slots; i++) { n += mali_group_dump_state(slots[i].group, buf + n, size - n); n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", slots[i].state); } return n; }
void mali_gp_job_delete(struct mali_gp_job *job) { MALI_DEBUG_ASSERT_POINTER(job); MALI_DEBUG_ASSERT(NULL == job->pp_tracker); MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); /* de-allocate the pre-allocated oom notifications */ if (NULL != job->oom_notification) { _mali_osk_notification_delete(job->oom_notification); job->oom_notification = NULL; } if (NULL != job->finished_notification) { _mali_osk_notification_delete(job->finished_notification); job->finished_notification = NULL; } _mali_osk_free(job); }
/** * Returns a physical job if a physical job is ready to run (no barrier present) */ MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_physical_job(void) { MALI_ASSERT_PP_SCHEDULER_LOCKED(); if (!_mali_osk_list_empty(&job_queue)) { struct mali_pp_job *job; MALI_DEBUG_ASSERT(job_queue_depth > 0); job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); if (!mali_pp_job_has_active_barrier(job)) { return job; } } return NULL; }
_mali_osk_errcode_t mali_allocation_engine_allocate_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_allocators, _mali_osk_list_t *tracking_list ) { memory_engine * engine = (memory_engine*)mem_engine; MALI_DEBUG_ASSERT_POINTER(engine); MALI_DEBUG_ASSERT_POINTER(descriptor); MALI_DEBUG_ASSERT_POINTER(physical_allocators); /* ASSERT that the list member has been initialized, even if it won't be * used for tracking. We need it to be initialized to see if we need to * delete it from a list in the release function. */ MALI_DEBUG_ASSERT( NULL != descriptor->list.next && NULL != descriptor->list.prev ); if (_MALI_OSK_ERR_OK == engine->mali_address->allocate(descriptor)) { _mali_osk_errcode_t res = _MALI_OSK_ERR_OK; if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE ) { res = engine->process_address->allocate(descriptor); } if ( _MALI_OSK_ERR_OK == res ) { /* address space setup OK, commit physical memory to the allocation */ mali_physical_memory_allocator * active_allocator = physical_allocators; struct mali_physical_memory_allocation * active_allocation_tracker = &descriptor->physical_allocation; u32 offset = 0; while ( NULL != active_allocator ) { switch (active_allocator->allocate(active_allocator->ctx, mem_engine, descriptor, &offset, active_allocation_tracker)) { case MALI_MEM_ALLOC_FINISHED: if ( NULL != tracking_list ) { /* Insert into the memory session list */ /* ASSERT that it is not already part of a list */ MALI_DEBUG_ASSERT( _mali_osk_list_empty( &descriptor->list ) ); _mali_osk_list_add( &descriptor->list, tracking_list ); } MALI_SUCCESS; /* all done */ case MALI_MEM_ALLOC_NONE: /* reuse current active_allocation_tracker */ MALI_DEBUG_PRINT( 4, ("Memory Engine Allocate: No allocation on %s, resorting to %s\n", ( active_allocator->name ) ? active_allocator->name : "UNNAMED", ( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") ); active_allocator = active_allocator->next; break; case MALI_MEM_ALLOC_PARTIAL: if (NULL != active_allocator->next) { /* need a new allocation tracker */ active_allocation_tracker->next = _mali_osk_calloc(1, sizeof(mali_physical_memory_allocation)); if (NULL != active_allocation_tracker->next) { active_allocation_tracker = active_allocation_tracker->next; MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate: Partial allocation on %s, resorting to %s\n", ( active_allocator->name ) ? active_allocator->name : "UNNAMED", ( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") ); active_allocator = active_allocator->next; break; } } /* FALL THROUGH */ case MALI_MEM_ALLOC_INTERNAL_FAILURE: active_allocator = NULL; /* end the while loop */ break; } } MALI_PRINT(("Memory allocate failed, could not allocate size %d kB.\n", descriptor->size/1024)); /* allocation failure, start cleanup */ /* loop over any potential partial allocations */ active_allocation_tracker = &descriptor->physical_allocation; while (NULL != active_allocation_tracker) { /* handle blank trackers which will show up during failure */ if (NULL != active_allocation_tracker->release) { active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle); } active_allocation_tracker = active_allocation_tracker->next; } /* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */ for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; ) { void * buf = active_allocation_tracker; active_allocation_tracker = active_allocation_tracker->next; _mali_osk_free(buf); } /* release the address spaces */ if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE ) { engine->process_address->release(descriptor); } } engine->mali_address->release(descriptor); } MALI_ERROR(_MALI_OSK_ERR_FAULT); }
static void mali_pp_scheduler_schedule(void) { u32 i; struct mali_pp_job *job; #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS struct mali_session_data * session; #endif MALI_ASSERT_PP_SCHEDULER_LOCKED(); if (0 < pause_count || 0 == num_slots_idle || _mali_osk_list_empty(&job_queue)) { MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", pause_count, num_slots_idle)); return; /* Nothing to do, so early out */ } #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP if ( num_slots_idle < num_slots ) { MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started, since only %d/%d cores are available\n", num_slots_idle,num_slots)); return; } #endif #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS /* Finding initial session for the PP cores */ job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); session = job->session; if ( num_slots != num_slots_idle ) { for (i = 0; (i < num_slots) ; i++) { if ( slots[i].state == MALI_PP_SLOT_STATE_IDLE ) { continue; } session = mali_group_get_session(slots[i].group); break; } } #endif for (i = 0; (i < num_slots) && (0 < num_slots_idle); i++) { u32 sub_job; if (_mali_osk_list_empty(&job_queue)) /* move this check down to where we know we have started all sub jobs for this job??? */ { break; /* No more jobs to schedule, so early out */ } if (MALI_PP_SLOT_STATE_IDLE != slots[i].state) { continue; } job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); /* All jobs on the job_queue should have unstarted sub jobs */ if (MALI_TRUE == mali_pp_job_has_active_barrier(job)) { if (MALI_TRUE == mali_pp_scheduler_session_has_running_jobs(mali_pp_job_get_session(job))) { /* There is already a running job from this session, so we need to enforce the barrier */ return; } else { /* Barrier is now enforced, update job object so we don't delay execution of sub-jobs */ mali_pp_job_barrier_enforced(job); } } #if MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED if ( (0==job->sub_jobs_started) && (num_slots_idle < num_slots) && (job->sub_job_count > num_slots_idle)) { MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job with %d subjobs not started, since only %d/%d cores are available\n", job->sub_job_count, num_slots_idle,num_slots)); return; } #endif #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS if ( job->session != session ) { MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started since existing job is from another application\n")); return; } #endif sub_job = mali_pp_job_get_first_unstarted_sub_job(job); MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Starting job %u (0x%08X) part %u/%u\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); if (_MALI_OSK_ERR_OK == mali_group_start_pp_job(slots[i].group, job, sub_job)) { MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job %u (0x%08X) part %u/%u started\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); /* Mark this sub job as started */ mali_pp_job_mark_sub_job_started(job, sub_job); /* Mark slot as busy */ slots[i].state = MALI_PP_SLOT_STATE_WORKING; slots[i].session = mali_pp_job_get_session(job); num_slots_idle--; if (!mali_pp_job_has_unstarted_sub_jobs(job)) { /* * All sub jobs have now started for this job, remove this job from the job queue. * The job will now only be referred to by the slots which are running it. * The last slot to complete will make sure it is returned to user space. */ _mali_osk_list_del(&job->list); #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP MALI_DEBUG_PRINT(6, ("Mali PP scheduler: Skip scheduling more jobs when MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP is set.\n")); return; #endif } } else { MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Failed to start PP job\n")); return; } } }