2 * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
11 #include "mali_soft_job.h"
13 #include "mali_osk_mali.h"
14 #include "mali_timeline.h"
15 #include "mali_session.h"
16 #include "mali_kernel_common.h"
17 #include "mali_uk_types.h"
18 #include "mali_scheduler.h"
20 MALI_STATIC_INLINE void mali_soft_job_system_lock(struct mali_soft_job_system *system)
22 MALI_DEBUG_ASSERT_POINTER(system);
23 _mali_osk_spinlock_irq_lock(system->lock);
24 MALI_DEBUG_PRINT(5, ("Mali Soft Job: soft system %p lock taken\n", system));
25 MALI_DEBUG_ASSERT(0 == system->lock_owner);
26 MALI_DEBUG_CODE(system->lock_owner = _mali_osk_get_tid());
29 MALI_STATIC_INLINE void mali_soft_job_system_unlock(struct mali_soft_job_system *system)
31 MALI_DEBUG_ASSERT_POINTER(system);
32 MALI_DEBUG_PRINT(5, ("Mali Soft Job: releasing soft system %p lock\n", system));
33 MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner);
34 MALI_DEBUG_CODE(system->lock_owner = 0);
35 _mali_osk_spinlock_irq_unlock(system->lock);
39 MALI_STATIC_INLINE void mali_soft_job_system_assert_locked(struct mali_soft_job_system *system)
41 MALI_DEBUG_ASSERT_POINTER(system);
42 MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner);
44 #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system) mali_soft_job_system_assert_locked(system)
46 #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system)
47 #endif /* defined(DEBUG) */
49 struct mali_soft_job_system *mali_soft_job_system_create(struct mali_session_data *session)
52 struct mali_soft_job_system *system;
53 struct mali_soft_job *job;
55 MALI_DEBUG_ASSERT_POINTER(session);
57 system = (struct mali_soft_job_system *) _mali_osk_calloc(1, sizeof(struct mali_soft_job_system));
62 system->session = session;
64 system->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
65 if (NULL == system->lock) {
66 mali_soft_job_system_destroy(system);
69 system->lock_owner = 0;
71 _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_free));
72 _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_used));
74 for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) {
75 job = &(system->jobs[i]);
76 _mali_osk_list_add(&(job->system_list), &(system->jobs_free));
78 job->state = MALI_SOFT_JOB_STATE_FREE;
85 void mali_soft_job_system_destroy(struct mali_soft_job_system *system)
87 MALI_DEBUG_ASSERT_POINTER(system);
89 /* All jobs should be free at this point. */
92 struct mali_soft_job *job;
94 for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i)
96 job = &(system->jobs[i]);
97 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state);
101 if (NULL != system) {
102 if (NULL != system->lock) {
103 _mali_osk_spinlock_irq_term(system->lock);
105 _mali_osk_free(system);
109 static struct mali_soft_job *mali_soft_job_system_alloc_job(struct mali_soft_job_system *system)
111 struct mali_soft_job *job;
113 MALI_DEBUG_ASSERT_POINTER(system);
114 MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
116 if (_mali_osk_list_empty(&(system->jobs_free))) {
117 /* No jobs available. */
121 /* Grab first job and move it to the used list. */
122 job = _MALI_OSK_LIST_ENTRY(system->jobs_free.next, struct mali_soft_job, system_list);
123 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state);
125 _mali_osk_list_move(&(job->system_list), &(system->jobs_used));
126 job->state = MALI_SOFT_JOB_STATE_ALLOCATED;
128 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
129 MALI_DEBUG_ASSERT(system == job->system);
134 static void mali_soft_job_system_free_job(struct mali_soft_job_system *system, struct mali_soft_job *job)
136 MALI_DEBUG_ASSERT_POINTER(job);
137 MALI_DEBUG_ASSERT_POINTER(system);
139 mali_soft_job_system_lock(job->system);
141 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE != job->state);
142 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
143 MALI_DEBUG_ASSERT(system == job->system);
145 job->state = MALI_SOFT_JOB_STATE_FREE;
146 _mali_osk_list_move(&(job->system_list), &(system->jobs_free));
148 mali_soft_job_system_unlock(job->system);
151 MALI_STATIC_INLINE struct mali_soft_job *mali_soft_job_system_lookup_job(struct mali_soft_job_system *system, u32 job_id)
153 MALI_DEBUG_ASSERT_POINTER(system);
154 MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
156 if (job_id < MALI_MAX_NUM_SOFT_JOBS) {
157 return &system->jobs[job_id];
163 void mali_soft_job_destroy(struct mali_soft_job *job)
165 MALI_DEBUG_ASSERT_POINTER(job);
166 MALI_DEBUG_ASSERT_POINTER(job->system);
168 MALI_DEBUG_PRINT(4, ("Mali Soft Job: destroying soft job %u (0x%08X)\n", job->id, job));
171 if (0 < _mali_osk_atomic_dec_return(&job->refcount)) return;
173 _mali_osk_atomic_term(&job->refcount);
175 if (NULL != job->activated_notification) {
176 _mali_osk_notification_delete(job->activated_notification);
177 job->activated_notification = NULL;
180 mali_soft_job_system_free_job(job->system, job);
184 struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u32 user_job)
186 struct mali_soft_job *job;
187 _mali_osk_notification_t *notification = NULL;
189 MALI_DEBUG_ASSERT_POINTER(system);
190 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_TYPE_USER_SIGNALED >= type);
192 if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) {
193 notification = _mali_osk_notification_create(_MALI_NOTIFICATION_SOFT_ACTIVATED, sizeof(_mali_uk_soft_job_activated_s));
194 if (unlikely(NULL == notification)) {
195 MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate notification"));
200 mali_soft_job_system_lock(system);
202 job = mali_soft_job_system_alloc_job(system);
204 mali_soft_job_system_unlock(system);
205 MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate job"));
206 _mali_osk_notification_delete(notification);
211 job->user_job = user_job;
212 job->activated = MALI_FALSE;
214 if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) {
215 job->activated_notification = notification;
218 _mali_osk_atomic_init(&job->refcount, 1);
220 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
221 MALI_DEBUG_ASSERT(system == job->system);
222 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
224 mali_soft_job_system_unlock(system);
229 mali_timeline_point mali_soft_job_start(struct mali_soft_job *job, struct mali_timeline_fence *fence)
231 mali_timeline_point point;
232 struct mali_soft_job_system *system;
234 MALI_DEBUG_ASSERT_POINTER(job);
235 MALI_DEBUG_ASSERT_POINTER(fence);
237 MALI_DEBUG_ASSERT_POINTER(job->system);
238 system = job->system;
240 MALI_DEBUG_ASSERT_POINTER(system->session);
241 MALI_DEBUG_ASSERT_POINTER(system->session->timeline_system);
243 mali_soft_job_system_lock(system);
245 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
246 job->state = MALI_SOFT_JOB_STATE_STARTED;
248 mali_soft_job_system_unlock(system);
250 MALI_DEBUG_PRINT(4, ("Mali Soft Job: starting soft job %u (0x%08X)\n", job->id, job));
252 mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_SOFT, fence, job);
253 point = mali_timeline_system_add_tracker(system->session->timeline_system, &job->tracker, MALI_TIMELINE_SOFT);
258 static mali_bool mali_soft_job_is_activated(void *data)
260 struct mali_soft_job *job;
262 job = (struct mali_soft_job *) data;
263 MALI_DEBUG_ASSERT_POINTER(job);
265 return job->activated;
268 _mali_osk_errcode_t mali_soft_job_system_signal_job(struct mali_soft_job_system *system, u32 job_id)
270 struct mali_soft_job *job;
271 struct mali_timeline_system *timeline_system;
272 mali_scheduler_mask schedule_mask;
274 MALI_DEBUG_ASSERT_POINTER(system);
276 mali_soft_job_system_lock(system);
278 job = mali_soft_job_system_lookup_job(system, job_id);
280 if (NULL == job || !(MALI_SOFT_JOB_STATE_STARTED == job->state || MALI_SOFT_JOB_STATE_TIMED_OUT == job->state)) {
281 mali_soft_job_system_unlock(system);
282 MALI_PRINT_ERROR(("Mali Soft Job: invalid soft job id %u", job_id));
283 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
286 if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) {
287 job->state = MALI_SOFT_JOB_STATE_SIGNALED;
288 mali_soft_job_system_unlock(system);
290 MALI_DEBUG_ASSERT(MALI_TRUE == job->activated);
291 MALI_DEBUG_PRINT(4, ("Mali Soft Job: soft job %u (0x%08X) was timed out\n", job->id, job));
292 mali_soft_job_destroy(job);
294 return _MALI_OSK_ERR_TIMEOUT;
297 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
299 job->state = MALI_SOFT_JOB_STATE_SIGNALED;
300 mali_soft_job_system_unlock(system);
302 /* Since the job now is in signaled state, timeouts from the timeline system will be
303 * ignored, and it is not possible to signal this job again. */
305 timeline_system = system->session->timeline_system;
306 MALI_DEBUG_ASSERT_POINTER(timeline_system);
308 /* Wait until activated. */
309 _mali_osk_wait_queue_wait_event(timeline_system->wait_queue, mali_soft_job_is_activated, (void *) job);
311 MALI_DEBUG_PRINT(4, ("Mali Soft Job: signaling soft job %u (0x%08X)\n", job->id, job));
313 schedule_mask = mali_timeline_tracker_release(&job->tracker);
314 mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
316 mali_soft_job_destroy(job);
318 return _MALI_OSK_ERR_OK;
321 static void mali_soft_job_send_activated_notification(struct mali_soft_job *job)
323 if (NULL != job->activated_notification) {
324 _mali_uk_soft_job_activated_s *res = job->activated_notification->result_buffer;
325 res->user_job = job->user_job;
326 mali_session_send_notification(job->system->session, job->activated_notification);
328 job->activated_notification = NULL;
331 void mali_soft_job_system_activate_job(struct mali_soft_job *job)
333 MALI_DEBUG_ASSERT_POINTER(job);
334 MALI_DEBUG_ASSERT_POINTER(job->system);
335 MALI_DEBUG_ASSERT_POINTER(job->system->session);
337 MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline activation for soft job %u (0x%08X).\n", job->id, job));
339 mali_soft_job_system_lock(job->system);
341 if (unlikely(job->system->session->is_aborting)) {
342 MALI_DEBUG_PRINT(3, ("Mali Soft Job: Soft job %u (0x%08X) activated while session is aborting.\n", job->id, job));
344 mali_soft_job_system_unlock(job->system);
346 /* Since we are in shutdown, we can ignore the scheduling bitmask. */
347 mali_timeline_tracker_release(&job->tracker);
348 mali_soft_job_destroy(job);
352 /* Send activated notification. */
353 mali_soft_job_send_activated_notification(job);
355 /* Wake up sleeping signaler. */
356 job->activated = MALI_TRUE;
357 _mali_osk_wait_queue_wake_up(job->tracker.system->wait_queue);
359 mali_soft_job_system_unlock(job->system);
362 mali_scheduler_mask mali_soft_job_system_timeout_job(struct mali_soft_job *job)
364 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
366 MALI_DEBUG_ASSERT_POINTER(job);
367 MALI_DEBUG_ASSERT_POINTER(job->system);
368 MALI_DEBUG_ASSERT_POINTER(job->system->session);
369 MALI_DEBUG_ASSERT(MALI_TRUE == job->activated);
371 MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline timeout for soft job %u (0x%08X).\n", job->id, job));
373 mali_soft_job_system_lock(job->system);
375 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state ||
376 MALI_SOFT_JOB_STATE_SIGNALED == job->state);
378 if (unlikely(job->system->session->is_aborting)) {
379 /* The session is aborting. This job will be released and destroyed by @ref
380 * mali_soft_job_system_abort(). */
381 mali_soft_job_system_unlock(job->system);
383 return MALI_SCHEDULER_MASK_EMPTY;
386 if (MALI_SOFT_JOB_STATE_STARTED != job->state) {
387 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state);
389 /* The job is about to be signaled, ignore timeout. */
390 MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeout on soft job %u (0x%08X) in signaled state.\n", job->id, job));
391 mali_soft_job_system_unlock(job->system);
392 return schedule_mask;
395 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
397 job->state = MALI_SOFT_JOB_STATE_TIMED_OUT;
398 _mali_osk_atomic_inc(&job->refcount);
400 mali_soft_job_system_unlock(job->system);
402 schedule_mask = mali_timeline_tracker_release(&job->tracker);
404 mali_soft_job_destroy(job);
406 return schedule_mask;
409 void mali_soft_job_system_abort(struct mali_soft_job_system *system)
412 struct mali_soft_job *job, *tmp;
413 _MALI_OSK_LIST_HEAD_STATIC_INIT(jobs);
415 MALI_DEBUG_ASSERT_POINTER(system);
416 MALI_DEBUG_ASSERT_POINTER(system->session);
417 MALI_DEBUG_ASSERT(system->session->is_aborting);
419 MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting soft job system for session 0x%08X.\n", system->session));
421 mali_soft_job_system_lock(system);
423 for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) {
424 job = &(system->jobs[i]);
426 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state ||
427 MALI_SOFT_JOB_STATE_STARTED == job->state ||
428 MALI_SOFT_JOB_STATE_TIMED_OUT == job->state);
430 if (MALI_SOFT_JOB_STATE_STARTED == job->state) {
431 /* If the job has been activated, we have to release the tracker and destroy
432 * the job. If not, the tracker will be released and the job destroyed when
433 * it is activated. */
434 if (MALI_TRUE == job->activated) {
435 MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting unsignaled soft job %u (0x%08X).\n", job->id, job));
437 job->state = MALI_SOFT_JOB_STATE_SIGNALED;
438 _mali_osk_list_move(&job->system_list, &jobs);
440 } else if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) {
441 MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting timed out soft job %u (0x%08X).\n", job->id, job));
443 /* We need to destroy this soft job. */
444 _mali_osk_list_move(&job->system_list, &jobs);
448 mali_soft_job_system_unlock(system);
450 /* Release and destroy jobs. */
451 _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &jobs, struct mali_soft_job, system_list) {
452 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state ||
453 MALI_SOFT_JOB_STATE_TIMED_OUT == job->state);
455 if (MALI_SOFT_JOB_STATE_SIGNALED == job->state) {
456 mali_timeline_tracker_release(&job->tracker);
459 /* Move job back to used list before destroying. */
460 _mali_osk_list_move(&job->system_list, &system->jobs_used);
462 mali_soft_job_destroy(job);