tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / common / mali_soft_job.c
1 /*
2  * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
3  * 
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.
6  * 
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.
9  */
10
11 #include "mali_soft_job.h"
12 #include "mali_osk.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"
19
20 MALI_STATIC_INLINE void mali_soft_job_system_lock(struct mali_soft_job_system *system)
21 {
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());
27 }
28
29 MALI_STATIC_INLINE void mali_soft_job_system_unlock(struct mali_soft_job_system *system)
30 {
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);
36 }
37
38 #if defined(DEBUG)
39 MALI_STATIC_INLINE void mali_soft_job_system_assert_locked(struct mali_soft_job_system *system)
40 {
41         MALI_DEBUG_ASSERT_POINTER(system);
42         MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner);
43 }
44 #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system) mali_soft_job_system_assert_locked(system)
45 #else
46 #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system)
47 #endif /* defined(DEBUG) */
48
49 struct mali_soft_job_system *mali_soft_job_system_create(struct mali_session_data *session)
50 {
51         u32 i;
52         struct mali_soft_job_system *system;
53         struct mali_soft_job *job;
54
55         MALI_DEBUG_ASSERT_POINTER(session);
56
57         system = (struct mali_soft_job_system *) _mali_osk_calloc(1, sizeof(struct mali_soft_job_system));
58         if (NULL == system) {
59                 return NULL;
60         }
61
62         system->session = session;
63
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);
67                 return NULL;
68         }
69         system->lock_owner = 0;
70
71         _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_free));
72         _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_used));
73
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));
77                 job->system = system;
78                 job->state = MALI_SOFT_JOB_STATE_FREE;
79                 job->id = i;
80         }
81
82         return system;
83 }
84
85 void mali_soft_job_system_destroy(struct mali_soft_job_system *system)
86 {
87         MALI_DEBUG_ASSERT_POINTER(system);
88
89         /* All jobs should be free at this point. */
90         MALI_DEBUG_CODE( {
91                 u32 i;
92                 struct mali_soft_job *job;
93
94                 for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i)
95                 {
96                         job = &(system->jobs[i]);
97                         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state);
98                 }
99         });
100
101         if (NULL != system) {
102                 if (NULL != system->lock) {
103                         _mali_osk_spinlock_irq_term(system->lock);
104                 }
105                 _mali_osk_free(system);
106         }
107 }
108
109 static struct mali_soft_job *mali_soft_job_system_alloc_job(struct mali_soft_job_system *system)
110 {
111         struct mali_soft_job *job;
112
113         MALI_DEBUG_ASSERT_POINTER(system);
114         MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
115
116         if (_mali_osk_list_empty(&(system->jobs_free))) {
117                 /* No jobs available. */
118                 return NULL;
119         }
120
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);
124
125         _mali_osk_list_move(&(job->system_list), &(system->jobs_used));
126         job->state = MALI_SOFT_JOB_STATE_ALLOCATED;
127
128         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
129         MALI_DEBUG_ASSERT(system == job->system);
130
131         return job;
132 }
133
134 static void mali_soft_job_system_free_job(struct mali_soft_job_system *system, struct mali_soft_job *job)
135 {
136         MALI_DEBUG_ASSERT_POINTER(job);
137         MALI_DEBUG_ASSERT_POINTER(system);
138
139         mali_soft_job_system_lock(job->system);
140
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);
144
145         job->state = MALI_SOFT_JOB_STATE_FREE;
146         _mali_osk_list_move(&(job->system_list), &(system->jobs_free));
147
148         mali_soft_job_system_unlock(job->system);
149 }
150
151 MALI_STATIC_INLINE struct mali_soft_job *mali_soft_job_system_lookup_job(struct mali_soft_job_system *system, u32 job_id)
152 {
153         MALI_DEBUG_ASSERT_POINTER(system);
154         MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
155
156         if (job_id < MALI_MAX_NUM_SOFT_JOBS) {
157                 return &system->jobs[job_id];
158         }
159
160         return NULL;
161 }
162
163 void mali_soft_job_destroy(struct mali_soft_job *job)
164 {
165         MALI_DEBUG_ASSERT_POINTER(job);
166         MALI_DEBUG_ASSERT_POINTER(job->system);
167
168         MALI_DEBUG_PRINT(4, ("Mali Soft Job: destroying soft job %u (0x%08X)\n", job->id, job));
169
170         if (NULL != job) {
171                 if (0 < _mali_osk_atomic_dec_return(&job->refcount)) return;
172
173                 _mali_osk_atomic_term(&job->refcount);
174
175                 if (NULL != job->activated_notification) {
176                         _mali_osk_notification_delete(job->activated_notification);
177                         job->activated_notification = NULL;
178                 }
179
180                 mali_soft_job_system_free_job(job->system, job);
181         }
182 }
183
184 struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u32 user_job)
185 {
186         struct mali_soft_job *job;
187         _mali_osk_notification_t *notification = NULL;
188
189         MALI_DEBUG_ASSERT_POINTER(system);
190         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_TYPE_USER_SIGNALED >= type);
191
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"));
196                         return NULL;
197                 }
198         }
199
200         mali_soft_job_system_lock(system);
201
202         job = mali_soft_job_system_alloc_job(system);
203         if (NULL == job) {
204                 mali_soft_job_system_unlock(system);
205                 MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate job"));
206                 _mali_osk_notification_delete(notification);
207                 return NULL;
208         }
209
210         job->type = type;
211         job->user_job = user_job;
212         job->activated = MALI_FALSE;
213
214         if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) {
215                 job->activated_notification = notification;
216         }
217
218         _mali_osk_atomic_init(&job->refcount, 1);
219
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);
223
224         mali_soft_job_system_unlock(system);
225
226         return job;
227 }
228
229 mali_timeline_point mali_soft_job_start(struct mali_soft_job *job, struct mali_timeline_fence *fence)
230 {
231         mali_timeline_point point;
232         struct mali_soft_job_system *system;
233
234         MALI_DEBUG_ASSERT_POINTER(job);
235         MALI_DEBUG_ASSERT_POINTER(fence);
236
237         MALI_DEBUG_ASSERT_POINTER(job->system);
238         system = job->system;
239
240         MALI_DEBUG_ASSERT_POINTER(system->session);
241         MALI_DEBUG_ASSERT_POINTER(system->session->timeline_system);
242
243         mali_soft_job_system_lock(system);
244
245         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
246         job->state = MALI_SOFT_JOB_STATE_STARTED;
247
248         mali_soft_job_system_unlock(system);
249
250         MALI_DEBUG_PRINT(4, ("Mali Soft Job: starting soft job %u (0x%08X)\n", job->id, job));
251
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);
254
255         return point;
256 }
257
258 static mali_bool mali_soft_job_is_activated(void *data)
259 {
260         struct mali_soft_job *job;
261
262         job = (struct mali_soft_job *) data;
263         MALI_DEBUG_ASSERT_POINTER(job);
264
265         return job->activated;
266 }
267
268 _mali_osk_errcode_t mali_soft_job_system_signal_job(struct mali_soft_job_system *system, u32 job_id)
269 {
270         struct mali_soft_job *job;
271         struct mali_timeline_system *timeline_system;
272         mali_scheduler_mask schedule_mask;
273
274         MALI_DEBUG_ASSERT_POINTER(system);
275
276         mali_soft_job_system_lock(system);
277
278         job = mali_soft_job_system_lookup_job(system, job_id);
279
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;
284         }
285
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);
289
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);
293
294                 return _MALI_OSK_ERR_TIMEOUT;
295         }
296
297         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
298
299         job->state = MALI_SOFT_JOB_STATE_SIGNALED;
300         mali_soft_job_system_unlock(system);
301
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. */
304
305         timeline_system = system->session->timeline_system;
306         MALI_DEBUG_ASSERT_POINTER(timeline_system);
307
308         /* Wait until activated. */
309         _mali_osk_wait_queue_wait_event(timeline_system->wait_queue, mali_soft_job_is_activated, (void *) job);
310
311         MALI_DEBUG_PRINT(4, ("Mali Soft Job: signaling soft job %u (0x%08X)\n", job->id, job));
312
313         schedule_mask = mali_timeline_tracker_release(&job->tracker);
314         mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
315
316         mali_soft_job_destroy(job);
317
318         return _MALI_OSK_ERR_OK;
319 }
320
321 static void mali_soft_job_send_activated_notification(struct mali_soft_job *job)
322 {
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);
327         }
328         job->activated_notification = NULL;
329 }
330
331 void mali_soft_job_system_activate_job(struct mali_soft_job *job)
332 {
333         MALI_DEBUG_ASSERT_POINTER(job);
334         MALI_DEBUG_ASSERT_POINTER(job->system);
335         MALI_DEBUG_ASSERT_POINTER(job->system->session);
336
337         MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline activation for soft job %u (0x%08X).\n", job->id, job));
338
339         mali_soft_job_system_lock(job->system);
340
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));
343
344                 mali_soft_job_system_unlock(job->system);
345
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);
349                 return;
350         }
351
352         /* Send activated notification. */
353         mali_soft_job_send_activated_notification(job);
354
355         /* Wake up sleeping signaler. */
356         job->activated = MALI_TRUE;
357         _mali_osk_wait_queue_wake_up(job->tracker.system->wait_queue);
358
359         mali_soft_job_system_unlock(job->system);
360 }
361
362 mali_scheduler_mask mali_soft_job_system_timeout_job(struct mali_soft_job *job)
363 {
364         mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
365
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);
370
371         MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline timeout for soft job %u (0x%08X).\n", job->id, job));
372
373         mali_soft_job_system_lock(job->system);
374
375         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED  == job->state ||
376                           MALI_SOFT_JOB_STATE_SIGNALED == job->state);
377
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);
382
383                 return MALI_SCHEDULER_MASK_EMPTY;
384         }
385
386         if (MALI_SOFT_JOB_STATE_STARTED != job->state) {
387                 MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state);
388
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;
393         }
394
395         MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
396
397         job->state = MALI_SOFT_JOB_STATE_TIMED_OUT;
398         _mali_osk_atomic_inc(&job->refcount);
399
400         mali_soft_job_system_unlock(job->system);
401
402         schedule_mask = mali_timeline_tracker_release(&job->tracker);
403
404         mali_soft_job_destroy(job);
405
406         return schedule_mask;
407 }
408
409 void mali_soft_job_system_abort(struct mali_soft_job_system *system)
410 {
411         u32 i;
412         struct mali_soft_job *job, *tmp;
413         _MALI_OSK_LIST_HEAD_STATIC_INIT(jobs);
414
415         MALI_DEBUG_ASSERT_POINTER(system);
416         MALI_DEBUG_ASSERT_POINTER(system->session);
417         MALI_DEBUG_ASSERT(system->session->is_aborting);
418
419         MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting soft job system for session 0x%08X.\n", system->session));
420
421         mali_soft_job_system_lock(system);
422
423         for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) {
424                 job = &(system->jobs[i]);
425
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);
429
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));
436
437                                 job->state = MALI_SOFT_JOB_STATE_SIGNALED;
438                                 _mali_osk_list_move(&job->system_list, &jobs);
439                         }
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));
442
443                         /* We need to destroy this soft job. */
444                         _mali_osk_list_move(&job->system_list, &jobs);
445                 }
446         }
447
448         mali_soft_job_system_unlock(system);
449
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);
454
455                 if (MALI_SOFT_JOB_STATE_SIGNALED == job->state) {
456                         mali_timeline_tracker_release(&job->tracker);
457                 }
458
459                 /* Move job back to used list before destroying. */
460                 _mali_osk_list_move(&job->system_list, &system->jobs_used);
461
462                 mali_soft_job_destroy(job);
463         }
464 }