예제 #1
0
struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *uargs, u32 id)
{
	struct mali_gp_job *job;
	u32 perf_counter_flag;

	job = _mali_osk_malloc(sizeof(struct mali_gp_job));
	if (NULL != job)
	{
		job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s));
		if (NULL == job->finished_notification)
		{
			_mali_osk_free(job);
			return NULL;
		}

		job->oom_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));
		if (NULL == job->oom_notification)
		{
			_mali_osk_notification_delete(job->finished_notification);
			_mali_osk_free(job);
			return NULL;
		}

		if (0 != copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_gp_start_job_s)))
		{
			_mali_osk_notification_delete(job->finished_notification);
			_mali_osk_notification_delete(job->oom_notification);
			_mali_osk_free(job);
			return NULL;
		}

		perf_counter_flag = mali_gp_job_get_perf_counter_flag(job);

		/* case when no counters came from user space
		 * so pass the debugfs / DS-5 provided global ones to the job object */
		if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) ||
				(perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)))
		{
			mali_gp_job_set_perf_counter_src0(job, mali_gp_job_get_gp_counter_src0());
			mali_gp_job_set_perf_counter_src1(job, mali_gp_job_get_gp_counter_src1());
		}

		_mali_osk_list_init(&job->list);
		job->session = session;
		job->id = id;
		job->heap_current_addr = job->uargs.frame_registers[4];
		job->perf_counter_value0 = 0;
		job->perf_counter_value1 = 0;
		job->pid = _mali_osk_get_pid();
		job->tid = _mali_osk_get_tid();

		return job;
	}

	return NULL;
}
_mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args )
{
	_mali_osk_notification_t * notification;
    _mali_osk_notification_queue_t *queue;

    /* check input */
	MALI_DEBUG_ASSERT_POINTER(args);
    MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);

    queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id);

	/* if the queue does not exist we're currently shutting down */
	if (NULL == queue)
	{
		MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n"));
		MALI_SUCCESS;
	}

	notification = _mali_osk_notification_create(args->type, 0);
	if ( NULL == notification)
	{
		MALI_PRINT_ERROR( ("Failed to create notification object\n")) ;
		return _MALI_OSK_ERR_NOMEM;
	}

	_mali_osk_notification_queue_send(queue, notification);

    MALI_SUCCESS; /* all ok */
}
예제 #3
0
void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job)
{
	_mali_osk_notification_t *notobj;

	notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));

	if (NULL != notobj)
	{
		_mali_uk_gp_job_suspended_s * jobres;

		mali_gp_scheduler_lock();

		jobres = (_mali_uk_gp_job_suspended_s *)notobj->result_buffer;

		jobres->user_job_ptr = mali_gp_job_get_user_id(job);
		jobres->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY;
		jobres->cookie = mali_gp_job_get_id(job);
		slot.returned_cookie = jobres->cookie;

		mali_session_send_notification(mali_gp_job_get_session(job), notobj);

		mali_gp_scheduler_unlock();
	}

	/*
	* If this function failed, then we could return the job to user space right away,
	* but there is a job timer anyway that will do that eventually.
	* This is not exactly a common case anyway.
	*/
}
예제 #4
0
static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success)
{
	_mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s));
	if (NULL != notobj)
	{
		_mali_uk_gp_job_finished_s *jobres = notobj->result_buffer;
		_mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
		jobres->user_job_ptr = mali_gp_job_get_user_id(job);
		if (MALI_TRUE == success)
		{
			jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
		}
		else
		{
			jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
		}

		jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job);
		jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job);
		jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job);

		mali_session_send_notification(mali_gp_job_get_session(job), notobj);
	}
	else
	{
		MALI_PRINT_ERROR(("Mali GP scheduler: Unable to allocate notification object\n"));
	}

	mali_gp_job_delete(job);
}
예제 #5
0
int mali_dump_memory_notify(_mali_uk_memory_usage_dumped_s __user *arg)
{
	struct mali_session_data *session, *tmp;
	_mali_osk_notification_t * notification;

	mali_session_lock();
	MALI_SESSION_FOREACH(session, tmp, link)
	{
		notification = _mali_osk_notification_create(_MALI_NOTIFCATION_MEMORY_USAGE_DUMP, sizeof(_mali_uk_memory_usage_dumped_s));
		if (NULL == notification)
		{
			MALI_PRINT_ERROR( ("Failed to create notification object\n"));
			mali_session_unlock();
			return -ENOMEM;
		}

		if (0 != copy_from_user(notification->result_buffer, arg, sizeof(_mali_uk_memory_usage_dumped_s)))
		{
			_mali_osk_notification_delete(notification);
			mali_session_unlock();
			return -EFAULT;
		}

		mali_session_send_notification(session, notification);
	}
예제 #6
0
void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job)
{
	_mali_osk_notification_t *notobj;

	notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));

	if (NULL != notobj)
	{
		_mali_uk_gp_job_suspended_s * jobres;

		mali_gp_scheduler_lock();

		jobres = (_mali_uk_gp_job_suspended_s *)notobj->result_buffer;

		jobres->user_job_ptr = mali_gp_job_get_user_id(job);
		jobres->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY;
		jobres->cookie = mali_gp_job_get_id(job);
		slot.returned_cookie = jobres->cookie;

		mali_session_send_notification(mali_gp_job_get_session(job), notobj);

		mali_gp_scheduler_unlock();
	}

}
_mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args)
{
	struct mali_session_data *session;
	struct mali_gp_job *resumed_job;
	_mali_osk_notification_t *new_notification = 0;

	MALI_DEBUG_ASSERT_POINTER(args);

	if (NULL == args->ctx)
	{
		return _MALI_OSK_ERR_INVALID_ARGS;
	}

	session = (struct mali_session_data*)args->ctx;
	if (NULL == session)
	{
		return _MALI_OSK_ERR_FAULT;
	}

	if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code)
	{
		new_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));

		if (NULL == new_notification)
		{
			MALI_PRINT_ERROR(("Mali GP scheduler: Failed to allocate notification object. Will abort GP job.\n"));
			mali_group_lock(slot.group);
			mali_group_abort_gp_job(slot.group, args->cookie);
			mali_group_unlock(slot.group);
			return _MALI_OSK_ERR_FAULT;
		}
	}

	mali_group_lock(slot.group);

	if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code)
	{
		MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1]));

		resumed_job = mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]);
		if (NULL != resumed_job)
		{
			resumed_job->oom_notification = new_notification;
			mali_group_unlock(slot.group);
			return _MALI_OSK_ERR_OK;
		}
		else
		{
			mali_group_unlock(slot.group);
			_mali_osk_notification_delete(new_notification);
			return _MALI_OSK_ERR_FAULT;
		}
	}

	MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie));
	mali_group_abort_gp_job(slot.group, args->cookie);
	mali_group_unlock(slot.group);
	return _MALI_OSK_ERR_OK;
}
예제 #8
0
void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args )
{
	_mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
	_mali_osk_notification_t *msg;
	mali_pmm_message_t *event;
	MALI_DEBUG_ASSERT_POINTER(pmm);
	MALI_DEBUG_ASSERT_POINTER(args);

	MALIPMM_DEBUG_PRINT( ("PMM: sending message\n") );

#if MALI_PMM_TRACE && MALI_PMM_TRACE_SENT_EVENTS
	_mali_pmm_trace_event_message( args, MALI_FALSE );
#endif

	msg = _mali_osk_notification_create( MALI_PMM_NOTIFICATION_TYPE, sizeof( mali_pmm_message_t ) );

	if( msg )
	{
		event = (mali_pmm_message_t *)msg->result_buffer;
		event->id = args->id;
		event->ts = _mali_osk_time_tickcount();
		event->data = args->data;
		
		_mali_osk_atomic_inc( &(pmm->messages_queued) );

		if( args->id > MALI_PMM_EVENT_INTERNALS )
		{
			/* Internal PMM message */
			_mali_osk_notification_queue_send( pmm->iqueue, msg );
			#if MALI_PMM_TRACE
				pmm->imessages_sent++;
			#endif
		}
		else
		{
			/* Real event */
			_mali_osk_notification_queue_send( pmm->queue, msg );
			#if MALI_PMM_TRACE
				pmm->messages_sent++;
			#endif
		}
	}
	else
	{
		MALI_PRINT_ERROR( ("PMM: Could not send message %d", args->id) );
		/* Make note of this OOM - which has caused a missed event */
		pmm->missed++;
	}
	
	/* Schedule time to look at the event or the fact we couldn't create an event */
	_mali_osk_irq_schedulework( pmm->irq );
}
static void mali_user_settings_notify(_mali_uk_user_setting_t setting, u32 value)
{
	struct mali_session_data *session, *tmp;

	mali_session_lock();
	MALI_SESSION_FOREACH(session, tmp, link)
	{
		_mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_SETTINGS_CHANGED, sizeof(_mali_uk_settings_changed_s));
		_mali_uk_settings_changed_s *data = notobj->result_buffer;
		data->setting = setting;
		data->value = value;

		mali_session_send_notification(session, notobj);
	}
예제 #10
0
struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u64 user_job)
{
	struct mali_soft_job *job;
	_mali_osk_notification_t *notification = NULL;

	MALI_DEBUG_ASSERT_POINTER(system);
	MALI_DEBUG_ASSERT((MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) ||
			  (MALI_SOFT_JOB_TYPE_SELF_SIGNALED == type));

	notification = _mali_osk_notification_create(_MALI_NOTIFICATION_SOFT_ACTIVATED, sizeof(_mali_uk_soft_job_activated_s));
	if (unlikely(NULL == notification)) {
		MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate notification"));
		return NULL;
	}

	job = _mali_osk_malloc(sizeof(struct mali_soft_job));
	if (unlikely(NULL == job)) {
		MALI_DEBUG_PRINT(2, ("Mali Soft Job: system alloc job failed. \n"));
		return NULL;
	}

	mali_soft_job_system_lock(system);

	job->system = system;
	job->id = system->last_job_id++;
	job->state = MALI_SOFT_JOB_STATE_ALLOCATED;

	_mali_osk_list_add(&(job->system_list), &(system->jobs_used));

	job->type = type;
	job->user_job = user_job;
	job->activated = MALI_FALSE;

	job->activated_notification = notification;

	_mali_osk_atomic_init(&job->refcount, 1);

	MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
	MALI_DEBUG_ASSERT(system == job->system);
	MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);

	mali_soft_job_system_unlock(system);

	return job;
}
static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job)
{
	if (MALI_FALSE == mali_pp_job_use_no_notification(job))
	{
		_mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s));
		if (NULL != notobj)
		{
			u32 i;
			u32 sub_jobs = mali_pp_job_get_sub_job_count(job);
			mali_bool success = mali_pp_job_was_success(job);

			_mali_uk_pp_job_finished_s *jobres = notobj->result_buffer;
			_mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
			jobres->user_job_ptr = mali_pp_job_get_user_id(job);
			if (MALI_TRUE == success)
			{
				jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
			}
			else
			{
				jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
			}

			for (i = 0; i < sub_jobs; i++)
			{
				jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i);
				jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i);
			}

			mali_session_send_notification(mali_pp_job_get_session(job), notobj);
		}
		else
		{
			MALI_PRINT_ERROR(("Mali PP scheduler: Unable to allocate notification object\n"));
		}
	}

	mali_pp_job_delete(job);
}
예제 #12
0
struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *uargs, u32 id, struct mali_timeline_tracker *pp_tracker)
{
	struct mali_gp_job *job;
	u32 perf_counter_flag;

	job = _mali_osk_malloc(sizeof(struct mali_gp_job));
	if (NULL != job) {
		job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s));
		if (NULL == job->finished_notification) {
			_mali_osk_free(job);
			return NULL;
		}

		job->oom_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));
		if (NULL == job->oom_notification) {
			_mali_osk_notification_delete(job->finished_notification);
			_mali_osk_free(job);
			return NULL;
		}

		if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_gp_start_job_s))) {
			_mali_osk_notification_delete(job->finished_notification);
			_mali_osk_notification_delete(job->oom_notification);
			_mali_osk_free(job);
			return NULL;
		}

		perf_counter_flag = mali_gp_job_get_perf_counter_flag(job);

		/* case when no counters came from user space
		 * so pass the debugfs / DS-5 provided global ones to the job object */
		if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) ||
		      (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE))) {
			mali_gp_job_set_perf_counter_src0(job, mali_gp_job_get_gp_counter_src0());
			mali_gp_job_set_perf_counter_src1(job, mali_gp_job_get_gp_counter_src1());
		}

		_mali_osk_list_init(&job->list);
		job->session = session;
		job->id = id;
		job->heap_current_addr = job->uargs.frame_registers[4];
		job->perf_counter_value0 = 0;
		job->perf_counter_value1 = 0;
		job->pid = _mali_osk_get_pid();
		job->tid = _mali_osk_get_tid();

		job->pp_tracker = pp_tracker;
		if (NULL != job->pp_tracker) {
			/* Take a reference on PP job's tracker that will be released when the GP
			   job is done. */
			mali_timeline_system_tracker_get(session->timeline_system, pp_tracker);
		}

		mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_GP, NULL, job);
		mali_timeline_fence_copy_uk_fence(&(job->tracker.fence), &(job->uargs.fence));

		return job;
	}

	return NULL;
}
예제 #13
0
struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *uargs, u32 id)
{
	struct mali_pp_job *job;
	u32 perf_counter_flag;

	job = _mali_osk_calloc(1, sizeof(struct mali_pp_job));
	if (NULL != job)
	{
		if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_pp_start_job_s)))
		{
			goto fail;
		}

		if (job->uargs.num_cores > _MALI_PP_MAX_SUB_JOBS)
		{
			MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n"));
			goto fail;
		}

		if (!mali_pp_job_use_no_notification(job))
		{
			job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s));
			if (NULL == job->finished_notification) goto fail;
		}

		perf_counter_flag = mali_pp_job_get_perf_counter_flag(job);

		/* case when no counters came from user space
		 * so pass the debugfs / DS-5 provided global ones to the job object */
		if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) ||
				(perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)))
		{
			mali_pp_job_set_perf_counter_src0(job, mali_pp_job_get_pp_counter_src0());
			mali_pp_job_set_perf_counter_src1(job, mali_pp_job_get_pp_counter_src1());
		}

		_mali_osk_list_init(&job->list);
		job->session = session;
		_mali_osk_list_init(&job->session_list);
		job->id = id;

		job->sub_jobs_num = job->uargs.num_cores ? job->uargs.num_cores : 1;
		job->pid = _mali_osk_get_pid();
		job->tid = _mali_osk_get_tid();

		job->num_memory_cookies = job->uargs.num_memory_cookies;
		if (job->num_memory_cookies > 0)
		{
			u32 size;

			if (job->uargs.num_memory_cookies > session->descriptor_mapping->current_nr_mappings)
			{
				MALI_PRINT_ERROR(("Mali PP job: Too many memory cookies specified in job object\n"));
				goto fail;
			}

			size = sizeof(*job->uargs.memory_cookies) * job->num_memory_cookies;

			job->memory_cookies = _mali_osk_malloc(size);
			if (NULL == job->memory_cookies)
			{
				MALI_PRINT_ERROR(("Mali PP job: Failed to allocate %d bytes of memory cookies!\n", size));
				goto fail;
			}

			if (0 != _mali_osk_copy_from_user(job->memory_cookies, job->uargs.memory_cookies, size))
			{
				MALI_PRINT_ERROR(("Mali PP job: Failed to copy %d bytes of memory cookies from user!\n", size));
				goto fail;
			}

#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
			job->num_dma_bufs = job->num_memory_cookies;
			job->dma_bufs = _mali_osk_calloc(job->num_dma_bufs, sizeof(struct mali_dma_buf_attachment *));
			if (NULL == job->dma_bufs)
			{
				MALI_PRINT_ERROR(("Mali PP job: Failed to allocate dma_bufs array!\n"));
				goto fail;
			}
#endif
		}
		else
		{
			job->memory_cookies = NULL;
		}

		return job;
	}

fail:
	if (NULL != job)
	{
		mali_pp_job_delete(job);
	}

	return NULL;
}
예제 #14
0
struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *uargs, u32 id)
{
	struct mali_pp_job *job;
	u32 perf_counter_flag;

	job = _mali_osk_malloc(sizeof(struct mali_pp_job));
	if (NULL != job)
	{
		u32 i;

		if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_pp_start_job_s)))
		{
			_mali_osk_free(job);
			return NULL;
		}

		if (job->uargs.num_cores > _MALI_PP_MAX_SUB_JOBS)
		{
			MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n"));
			_mali_osk_free(job);
			return NULL;
		}

		if (!mali_pp_job_use_no_notification(job))
		{
			job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s));
			if (NULL == job->finished_notification)
			{
				_mali_osk_free(job);
				return NULL;
			}
		}
		else
		{
			job->finished_notification = NULL;
		}

		perf_counter_flag = mali_pp_job_get_perf_counter_flag(job);

		/* case when no counters came from user space
		 * so pass the debugfs / DS-5 provided global ones to the job object */
		if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) ||
				(perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)))
		{
			mali_pp_job_set_perf_counter_src0(job, mali_pp_job_get_pp_counter_src0());
			mali_pp_job_set_perf_counter_src1(job, mali_pp_job_get_pp_counter_src1());
		}

		_mali_osk_list_init(&job->list);
		job->session = session;
		_mali_osk_list_init(&job->session_list);
		job->id = id;

		for (i = 0; i < job->uargs.num_cores; i++)
		{
			job->perf_counter_value0[i] = 0;
			job->perf_counter_value1[i] = 0;
		}
		job->sub_jobs_num = job->uargs.num_cores ? job->uargs.num_cores : 1;
		job->sub_jobs_started = 0;
		job->sub_jobs_completed = 0;
		job->sub_job_errors = 0;
		job->pid = _mali_osk_get_pid();
		job->tid = _mali_osk_get_tid();
#if defined(MTK_CONFIG_SYNC)
		job->sync_point = NULL;
		job->pre_fence = NULL;
		job->sync_work = NULL;
#endif

		return job;
	}

	return NULL;
}
struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session,
				       _mali_uk_pp_start_job_s __user *uargs, u32 id)
{
	struct mali_pp_job *job;
	u32 perf_counter_flag;

	job = _mali_osk_calloc(1, sizeof(struct mali_pp_job));
	if (NULL != job) {
		if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_pp_start_job_s))) {
			goto fail;
		}

		if (job->uargs.num_cores > _MALI_PP_MAX_SUB_JOBS) {
			MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n"));
			goto fail;
		}

		if (!mali_pp_job_use_no_notification(job)) {
			job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s));
			if (NULL == job->finished_notification) goto fail;
		}

		perf_counter_flag = mali_pp_job_get_perf_counter_flag(job);

		/* case when no counters came from user space
		 * so pass the debugfs / DS-5 provided global ones to the job object */
		if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) ||
		      (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE))) {
			u32 sub_job_count = _mali_osk_atomic_read(&pp_counter_per_sub_job_count);

			/* These counters apply for all virtual jobs, and where no per sub job counter is specified */
			job->uargs.perf_counter_src0 = pp_counter_src0;
			job->uargs.perf_counter_src1 = pp_counter_src1;

			/* We only copy the per sub job array if it is enabled with at least one counter */
			if (0 < sub_job_count) {
				job->perf_counter_per_sub_job_count = sub_job_count;
				_mali_osk_memcpy(job->perf_counter_per_sub_job_src0, pp_counter_per_sub_job_src0, sizeof(pp_counter_per_sub_job_src0));
				_mali_osk_memcpy(job->perf_counter_per_sub_job_src1, pp_counter_per_sub_job_src1, sizeof(pp_counter_per_sub_job_src1));
			}
		}

		_mali_osk_list_init(&job->list);
		job->session = session;
		_mali_osk_list_init(&job->session_list);
		job->id = id;

		job->sub_jobs_num = job->uargs.num_cores ? job->uargs.num_cores : 1;
		job->pid = _mali_osk_get_pid();
		job->tid = _mali_osk_get_tid();

		job->num_memory_cookies = job->uargs.num_memory_cookies;
		if (job->num_memory_cookies > 0) {
			u32 size;
			u32 __user *memory_cookies = (u32 __user *)(uintptr_t)job->uargs.memory_cookies;

			if (job->uargs.num_memory_cookies > session->descriptor_mapping->current_nr_mappings) {
				MALI_PRINT_ERROR(("Mali PP job: Too many memory cookies specified in job object\n"));
				goto fail;
			}

			size = sizeof(*memory_cookies) * job->num_memory_cookies;

			job->memory_cookies = _mali_osk_malloc(size);
			if (NULL == job->memory_cookies) {
				MALI_PRINT_ERROR(("Mali PP job: Failed to allocate %d bytes of memory cookies!\n", size));
				goto fail;
			}

			if (0 != _mali_osk_copy_from_user(job->memory_cookies, memory_cookies, size)) {
				MALI_PRINT_ERROR(("Mali PP job: Failed to copy %d bytes of memory cookies from user!\n", size));
				goto fail;
			}

#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
			job->num_dma_bufs = job->num_memory_cookies;
			job->dma_bufs = _mali_osk_calloc(job->num_dma_bufs, sizeof(struct mali_dma_buf_attachment *));
			if (NULL == job->dma_bufs) {
				MALI_PRINT_ERROR(("Mali PP job: Failed to allocate dma_bufs array!\n"));
				goto fail;
			}
#endif
		}

		/* Prepare DMA command buffer to start job, if it is virtual. */
		if (mali_pp_job_is_virtual_group_job(job)) {
			struct mali_pp_core *core;
			_mali_osk_errcode_t err =  mali_dma_get_cmd_buf(&job->dma_cmd_buf);

			if (_MALI_OSK_ERR_OK != err) {
				MALI_PRINT_ERROR(("Mali PP job: Failed to allocate DMA command buffer\n"));
				goto fail;
			}

			core = mali_pp_scheduler_get_virtual_pp();
			MALI_DEBUG_ASSERT_POINTER(core);

			mali_pp_job_dma_cmd_prepare(core, job, 0, &job->dma_cmd_buf);
		}

		if (_MALI_OSK_ERR_OK != mali_pp_job_check(job)) {
			/* Not a valid job. */
			goto fail;
		}

		mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_PP, NULL, job);
		mali_timeline_fence_copy_uk_fence(&(job->tracker.fence), &(job->uargs.fence));

		return job;
	}

fail:
	if (NULL != job) {
		mali_pp_job_delete(job);
	}

	return NULL;
}
static void mali_user_settings_notify(_mali_uk_user_setting_t setting, u32 value)
{
	mali_bool done = MALI_FALSE;

	/*
	 * This function gets a bit complicated because we can't hold the session lock while
	 * allocating notification objects.
	 */

	while (!done) {
		u32 i;
		u32 num_sessions_alloc;
		u32 num_sessions_with_lock;
		u32 used_notification_objects = 0;
		_mali_osk_notification_t **notobjs;

		/* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */
		num_sessions_alloc = mali_session_get_count();
		if (0 == num_sessions_alloc) {
			/* No sessions to report to */
			return;
		}

		notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc);
		if (NULL == notobjs) {
			MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n"));
			return;
		}

		for (i = 0; i < num_sessions_alloc; i++) {
			notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_SETTINGS_CHANGED,
			             sizeof(_mali_uk_settings_changed_s));
			if (NULL != notobjs[i]) {
				_mali_uk_settings_changed_s *data;
				data = notobjs[i]->result_buffer;

				data->setting = setting;
				data->value = value;
			} else {
				MALI_PRINT_ERROR(("Failed to notify user space session about setting change (alloc failure %u)\n", i));
			}
		}

		mali_session_lock();

		/* number of sessions will not change while we hold the lock */
		num_sessions_with_lock = mali_session_get_count();

		if (num_sessions_alloc >= num_sessions_with_lock) {
			/* We have allocated enough notification objects for all the sessions atm */
			struct mali_session_data *session, *tmp;
			MALI_SESSION_FOREACH(session, tmp, link) {
				MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc);
				if (NULL != notobjs[used_notification_objects]) {
					mali_session_send_notification(session, notobjs[used_notification_objects]);
					notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */
				}
				used_notification_objects++;
			}
			done = MALI_TRUE;
		}

		mali_session_unlock();

		/* Delete any remaining/unused notification objects */
		for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) {
			if (NULL != notobjs[used_notification_objects]) {
				_mali_osk_notification_delete(notobjs[used_notification_objects]);
			}
		}

		_mali_osk_free(notobjs);
	}