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);
}
Example #6
0
/**
 * 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;
		}
	}
}