2 * Copyright (C) 2012-2016 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_scheduler.h"
12 #include "mali_kernel_common.h"
14 #include "mali_osk_profiling.h"
15 #include "mali_kernel_utilization.h"
16 #include "mali_timeline.h"
17 #include "mali_gp_job.h"
18 #include "mali_pp_job.h"
19 #include "mali_executor.h"
20 #include "mali_group.h"
21 #include <linux/wait.h>
22 #include <linux/sched.h>
23 #include "mali_pm_metrics.h"
25 #if defined(CONFIG_DMA_SHARED_BUFFER)
26 #include "mali_memory_dma_buf.h"
27 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
28 #include "mali_dma_fence.h"
29 #include <linux/dma-buf.h>
33 #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
34 #include <linux/sched.h>
35 #include <trace/events/gpu.h>
38 * ---------- static defines/constants ----------
42 * If dma_buf with map on demand is used, we defer job queue
43 * if in atomic context, since both might sleep.
45 #if defined(CONFIG_DMA_SHARED_BUFFER)
46 #if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
47 #define MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE 1
53 * ---------- global variables (exported due to inline functions) ----------
56 /* Lock protecting this module */
57 _mali_osk_spinlock_irq_t *mali_scheduler_lock_obj = NULL;
59 /* Queue of jobs to be executed on the GP group */
60 struct mali_scheduler_job_queue job_queue_gp;
62 /* Queue of PP jobs */
63 struct mali_scheduler_job_queue job_queue_pp;
65 _mali_osk_atomic_t mali_job_id_autonumber;
66 _mali_osk_atomic_t mali_job_cache_order_autonumber;
68 * ---------- static variables ----------
71 _mali_osk_wq_work_t *scheduler_wq_pp_job_delete = NULL;
72 _mali_osk_spinlock_irq_t *scheduler_pp_job_delete_lock = NULL;
73 static _MALI_OSK_LIST_HEAD_STATIC_INIT(scheduler_pp_job_deletion_queue);
75 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
76 static _mali_osk_wq_work_t *scheduler_wq_pp_job_queue = NULL;
77 static _mali_osk_spinlock_irq_t *scheduler_pp_job_queue_lock = NULL;
78 static _MALI_OSK_LIST_HEAD_STATIC_INIT(scheduler_pp_job_queue_list);
82 * ---------- Forward declaration of static functions ----------
85 static mali_timeline_point mali_scheduler_submit_gp_job(
86 struct mali_session_data *session, struct mali_gp_job *job);
87 static _mali_osk_errcode_t mali_scheduler_submit_pp_job(
88 struct mali_session_data *session, struct mali_pp_job *job, mali_timeline_point *point);
90 static mali_bool mali_scheduler_queue_gp_job(struct mali_gp_job *job);
91 static mali_bool mali_scheduler_queue_pp_job(struct mali_pp_job *job);
93 static void mali_scheduler_return_gp_job_to_user(struct mali_gp_job *job,
96 static void mali_scheduler_deferred_pp_job_delete(struct mali_pp_job *job);
97 void mali_scheduler_do_pp_job_delete(void *arg);
99 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
100 static void mali_scheduler_deferred_pp_job_queue(struct mali_pp_job *job);
101 static void mali_scheduler_do_pp_job_queue(void *arg);
102 #endif /* defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE) */
105 * ---------- Actual implementation ----------
108 _mali_osk_errcode_t mali_scheduler_initialize(void)
110 _mali_osk_atomic_init(&mali_job_id_autonumber, 0);
111 _mali_osk_atomic_init(&mali_job_cache_order_autonumber, 0);
113 _MALI_OSK_INIT_LIST_HEAD(&job_queue_gp.normal_pri);
114 _MALI_OSK_INIT_LIST_HEAD(&job_queue_gp.high_pri);
115 job_queue_gp.depth = 0;
116 job_queue_gp.big_job_num = 0;
118 _MALI_OSK_INIT_LIST_HEAD(&job_queue_pp.normal_pri);
119 _MALI_OSK_INIT_LIST_HEAD(&job_queue_pp.high_pri);
120 job_queue_pp.depth = 0;
121 job_queue_pp.big_job_num = 0;
123 mali_scheduler_lock_obj = _mali_osk_spinlock_irq_init(
124 _MALI_OSK_LOCKFLAG_ORDERED,
125 _MALI_OSK_LOCK_ORDER_SCHEDULER);
126 if (NULL == mali_scheduler_lock_obj) {
127 mali_scheduler_terminate();
130 scheduler_wq_pp_job_delete = _mali_osk_wq_create_work(
131 mali_scheduler_do_pp_job_delete, NULL);
132 if (NULL == scheduler_wq_pp_job_delete) {
133 mali_scheduler_terminate();
134 return _MALI_OSK_ERR_FAULT;
137 scheduler_pp_job_delete_lock = _mali_osk_spinlock_irq_init(
138 _MALI_OSK_LOCKFLAG_ORDERED,
139 _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
140 if (NULL == scheduler_pp_job_delete_lock) {
141 mali_scheduler_terminate();
142 return _MALI_OSK_ERR_FAULT;
145 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
146 scheduler_wq_pp_job_queue = _mali_osk_wq_create_work(
147 mali_scheduler_do_pp_job_queue, NULL);
148 if (NULL == scheduler_wq_pp_job_queue) {
149 mali_scheduler_terminate();
150 return _MALI_OSK_ERR_FAULT;
153 scheduler_pp_job_queue_lock = _mali_osk_spinlock_irq_init(
154 _MALI_OSK_LOCKFLAG_ORDERED,
155 _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
156 if (NULL == scheduler_pp_job_queue_lock) {
157 mali_scheduler_terminate();
158 return _MALI_OSK_ERR_FAULT;
160 #endif /* defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE) */
162 return _MALI_OSK_ERR_OK;
165 void mali_scheduler_terminate(void)
167 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
168 if (NULL != scheduler_pp_job_queue_lock) {
169 _mali_osk_spinlock_irq_term(scheduler_pp_job_queue_lock);
170 scheduler_pp_job_queue_lock = NULL;
173 if (NULL != scheduler_wq_pp_job_queue) {
174 _mali_osk_wq_delete_work(scheduler_wq_pp_job_queue);
175 scheduler_wq_pp_job_queue = NULL;
177 #endif /* defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE) */
179 if (NULL != scheduler_pp_job_delete_lock) {
180 _mali_osk_spinlock_irq_term(scheduler_pp_job_delete_lock);
181 scheduler_pp_job_delete_lock = NULL;
184 if (NULL != scheduler_wq_pp_job_delete) {
185 _mali_osk_wq_delete_work(scheduler_wq_pp_job_delete);
186 scheduler_wq_pp_job_delete = NULL;
189 if (NULL != mali_scheduler_lock_obj) {
190 _mali_osk_spinlock_irq_term(mali_scheduler_lock_obj);
191 mali_scheduler_lock_obj = NULL;
194 _mali_osk_atomic_term(&mali_job_cache_order_autonumber);
195 _mali_osk_atomic_term(&mali_job_id_autonumber);
198 u32 mali_scheduler_job_physical_head_count(mali_bool gpu_mode_is_secure)
201 * Count how many physical sub jobs are present from the head of queue
202 * until the first virtual job is present.
203 * Early out when we have reached maximum number of PP cores (8)
206 struct mali_pp_job *job;
207 struct mali_pp_job *temp;
209 /* Check for partially started normal pri jobs */
210 if (!_mali_osk_list_empty(&job_queue_pp.normal_pri)) {
211 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
213 job = _MALI_OSK_LIST_ENTRY(job_queue_pp.normal_pri.next,
214 struct mali_pp_job, list);
216 MALI_DEBUG_ASSERT_POINTER(job);
218 if (MALI_TRUE == mali_pp_job_has_started_sub_jobs(job)) {
220 * Remember; virtual jobs can't be queued and started
221 * at the same time, so this must be a physical job
223 if ((MALI_FALSE == gpu_mode_is_secure && MALI_FALSE == mali_pp_job_is_protected_job(job))
224 || (MALI_TRUE == gpu_mode_is_secure && MALI_TRUE == mali_pp_job_is_protected_job(job))) {
226 count += mali_pp_job_unstarted_sub_job_count(job);
227 if (MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS <= count) {
228 return MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS;
234 _MALI_OSK_LIST_FOREACHENTRY(job, temp, &job_queue_pp.high_pri,
235 struct mali_pp_job, list) {
236 if ((MALI_FALSE == mali_pp_job_is_virtual(job))
237 && ((MALI_FALSE == gpu_mode_is_secure && MALI_FALSE == mali_pp_job_is_protected_job(job))
238 || (MALI_TRUE == gpu_mode_is_secure && MALI_TRUE == mali_pp_job_is_protected_job(job)))) {
240 count += mali_pp_job_unstarted_sub_job_count(job);
241 if (MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS <= count) {
242 return MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS;
245 /* Came across a virtual job, so stop counting */
250 _MALI_OSK_LIST_FOREACHENTRY(job, temp, &job_queue_pp.normal_pri,
251 struct mali_pp_job, list) {
252 if ((MALI_FALSE == mali_pp_job_is_virtual(job))
253 && (MALI_FALSE == mali_pp_job_has_started_sub_jobs(job))
254 && ((MALI_FALSE == gpu_mode_is_secure && MALI_FALSE == mali_pp_job_is_protected_job(job))
255 || (MALI_TRUE == gpu_mode_is_secure && MALI_TRUE == mali_pp_job_is_protected_job(job)))) {
257 count += mali_pp_job_unstarted_sub_job_count(job);
258 if (MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS <= count) {
259 return MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS;
262 /* Came across a virtual job, so stop counting */
269 struct mali_pp_job *mali_scheduler_job_pp_next(void)
271 struct mali_pp_job *job;
272 struct mali_pp_job *temp;
274 MALI_DEBUG_ASSERT_LOCK_HELD(mali_scheduler_lock_obj);
276 /* Check for partially started normal pri jobs */
277 if (!_mali_osk_list_empty(&job_queue_pp.normal_pri)) {
278 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
280 job = _MALI_OSK_LIST_ENTRY(job_queue_pp.normal_pri.next,
281 struct mali_pp_job, list);
283 MALI_DEBUG_ASSERT_POINTER(job);
285 if (MALI_TRUE == mali_pp_job_has_started_sub_jobs(job)) {
290 _MALI_OSK_LIST_FOREACHENTRY(job, temp, &job_queue_pp.high_pri,
291 struct mali_pp_job, list) {
295 _MALI_OSK_LIST_FOREACHENTRY(job, temp, &job_queue_pp.normal_pri,
296 struct mali_pp_job, list) {
303 mali_bool mali_scheduler_job_next_is_virtual(void)
305 struct mali_pp_job *job;
307 job = mali_scheduler_job_pp_virtual_peek();
309 MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job));
317 struct mali_gp_job *mali_scheduler_job_gp_get(void)
319 _mali_osk_list_t *queue;
320 struct mali_gp_job *job = NULL;
322 MALI_DEBUG_ASSERT_LOCK_HELD(mali_scheduler_lock_obj);
323 MALI_DEBUG_ASSERT(0 < job_queue_gp.depth);
324 MALI_DEBUG_ASSERT(job_queue_gp.big_job_num <= job_queue_gp.depth);
326 if (!_mali_osk_list_empty(&job_queue_gp.high_pri)) {
327 queue = &job_queue_gp.high_pri;
329 queue = &job_queue_gp.normal_pri;
330 MALI_DEBUG_ASSERT(!_mali_osk_list_empty(queue));
333 job = _MALI_OSK_LIST_ENTRY(queue->next, struct mali_gp_job, list);
335 MALI_DEBUG_ASSERT_POINTER(job);
337 mali_gp_job_list_remove(job);
338 job_queue_gp.depth--;
340 job_queue_gp.big_job_num --;
341 if (job_queue_gp.big_job_num < MALI_MAX_PENDING_BIG_JOB) {
342 /* wake up process */
343 wait_queue_head_t *queue = mali_session_get_wait_queue();
350 struct mali_pp_job *mali_scheduler_job_pp_physical_peek(void)
352 struct mali_pp_job *job = NULL;
353 struct mali_pp_job *tmp_job = NULL;
355 MALI_DEBUG_ASSERT_LOCK_HELD(mali_scheduler_lock_obj);
358 * For PP jobs we favour partially started jobs in normal
359 * priority queue over unstarted jobs in high priority queue
362 if (!_mali_osk_list_empty(&job_queue_pp.normal_pri)) {
363 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
365 tmp_job = _MALI_OSK_LIST_ENTRY(job_queue_pp.normal_pri.next,
366 struct mali_pp_job, list);
367 MALI_DEBUG_ASSERT(NULL != tmp_job);
369 if (MALI_FALSE == mali_pp_job_is_virtual(tmp_job)) {
375 MALI_FALSE == mali_pp_job_has_started_sub_jobs(job)) {
377 * There isn't a partially started job in normal queue, so
378 * look in high priority queue.
380 if (!_mali_osk_list_empty(&job_queue_pp.high_pri)) {
381 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
383 tmp_job = _MALI_OSK_LIST_ENTRY(job_queue_pp.high_pri.next,
384 struct mali_pp_job, list);
385 MALI_DEBUG_ASSERT(NULL != tmp_job);
387 if (MALI_FALSE == mali_pp_job_is_virtual(tmp_job)) {
396 struct mali_pp_job *mali_scheduler_job_pp_virtual_peek(void)
398 struct mali_pp_job *job = NULL;
399 struct mali_pp_job *tmp_job = NULL;
401 MALI_DEBUG_ASSERT_LOCK_HELD(mali_scheduler_lock_obj);
403 if (!_mali_osk_list_empty(&job_queue_pp.high_pri)) {
404 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
406 tmp_job = _MALI_OSK_LIST_ENTRY(job_queue_pp.high_pri.next,
407 struct mali_pp_job, list);
409 if (MALI_TRUE == mali_pp_job_is_virtual(tmp_job)) {
415 if (!_mali_osk_list_empty(&job_queue_pp.normal_pri)) {
416 MALI_DEBUG_ASSERT(0 < job_queue_pp.depth);
418 tmp_job = _MALI_OSK_LIST_ENTRY(job_queue_pp.normal_pri.next,
419 struct mali_pp_job, list);
421 if (MALI_TRUE == mali_pp_job_is_virtual(tmp_job)) {
430 struct mali_pp_job *mali_scheduler_job_pp_physical_get(u32 *sub_job)
432 struct mali_pp_job *job = mali_scheduler_job_pp_physical_peek();
434 MALI_DEBUG_ASSERT(MALI_FALSE == mali_pp_job_is_virtual(job));
437 *sub_job = mali_pp_job_get_first_unstarted_sub_job(job);
439 mali_pp_job_mark_sub_job_started(job, *sub_job);
440 if (MALI_FALSE == mali_pp_job_has_unstarted_sub_jobs(job)) {
441 /* Remove from queue when last sub job has been retrieved */
442 mali_pp_job_list_remove(job);
445 job_queue_pp.depth--;
448 * Job about to start so it is no longer be
449 * possible to discard WB
451 mali_pp_job_fb_lookup_remove(job);
457 struct mali_pp_job *mali_scheduler_job_pp_virtual_get(void)
459 struct mali_pp_job *job = mali_scheduler_job_pp_virtual_peek();
461 MALI_DEBUG_ASSERT(MALI_TRUE == mali_pp_job_is_virtual(job));
464 MALI_DEBUG_ASSERT(0 ==
465 mali_pp_job_get_first_unstarted_sub_job(job));
466 MALI_DEBUG_ASSERT(1 ==
467 mali_pp_job_get_sub_job_count(job));
469 mali_pp_job_mark_sub_job_started(job, 0);
471 mali_pp_job_list_remove(job);
473 job_queue_pp.depth--;
476 * Job about to start so it is no longer be
477 * possible to discard WB
479 mali_pp_job_fb_lookup_remove(job);
485 mali_scheduler_mask mali_scheduler_activate_gp_job(struct mali_gp_job *job)
487 MALI_DEBUG_ASSERT_POINTER(job);
489 MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Timeline activation for job %u (0x%08X).\n",
490 mali_gp_job_get_id(job), job));
492 mali_scheduler_lock();
494 if (!mali_scheduler_queue_gp_job(job)) {
495 /* Failed to enqueue job, release job (with error) */
497 mali_scheduler_unlock();
499 mali_timeline_tracker_release(mali_gp_job_get_tracker(job));
500 mali_gp_job_signal_pp_tracker(job, MALI_FALSE);
502 /* This will notify user space and close the job object */
503 mali_scheduler_complete_gp_job(job, MALI_FALSE,
504 MALI_TRUE, MALI_FALSE);
506 return MALI_SCHEDULER_MASK_EMPTY;
509 mali_scheduler_unlock();
511 return MALI_SCHEDULER_MASK_GP;
514 mali_scheduler_mask mali_scheduler_activate_pp_job(struct mali_pp_job *job)
516 MALI_DEBUG_ASSERT_POINTER(job);
518 MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Timeline activation for job %u (0x%08X).\n",
519 mali_pp_job_get_id(job), job));
521 if (MALI_TRUE == mali_timeline_tracker_activation_error(
522 mali_pp_job_get_tracker(job))) {
523 MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Job %u (0x%08X) activated with error, aborting.\n",
524 mali_pp_job_get_id(job), job));
526 mali_scheduler_lock();
527 mali_pp_job_fb_lookup_remove(job);
528 mali_pp_job_mark_unstarted_failed(job);
529 mali_scheduler_unlock();
531 mali_timeline_tracker_release(mali_pp_job_get_tracker(job));
533 /* This will notify user space and close the job object */
534 mali_scheduler_complete_pp_job(job, 0, MALI_TRUE, MALI_FALSE);
536 return MALI_SCHEDULER_MASK_EMPTY;
539 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
540 if (mali_pp_job_needs_dma_buf_mapping(job)) {
541 mali_scheduler_deferred_pp_job_queue(job);
542 return MALI_SCHEDULER_MASK_EMPTY;
544 #endif /* defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE) */
546 mali_scheduler_lock();
548 if (!mali_scheduler_queue_pp_job(job)) {
549 /* Failed to enqueue job, release job (with error) */
550 mali_pp_job_fb_lookup_remove(job);
551 mali_pp_job_mark_unstarted_failed(job);
552 mali_scheduler_unlock();
554 mali_timeline_tracker_release(mali_pp_job_get_tracker(job));
556 /* This will notify user space and close the job object */
557 mali_scheduler_complete_pp_job(job, 0, MALI_TRUE, MALI_FALSE);
559 return MALI_SCHEDULER_MASK_EMPTY;
562 mali_scheduler_unlock();
563 return MALI_SCHEDULER_MASK_PP;
566 void mali_scheduler_complete_gp_job(struct mali_gp_job *job,
568 mali_bool user_notification,
571 if (user_notification) {
572 mali_scheduler_return_gp_job_to_user(job, success);
576 _mali_osk_pm_dev_ref_put();
578 if (mali_utilization_enabled()) {
579 mali_utilization_gp_end();
581 mali_pm_record_gpu_idle(MALI_TRUE);
584 mali_gp_job_delete(job);
587 void mali_scheduler_complete_pp_job(struct mali_pp_job *job,
588 u32 num_cores_in_virtual,
589 mali_bool user_notification,
592 job->user_notification = user_notification;
593 job->num_pp_cores_in_virtual = num_cores_in_virtual;
595 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
596 if (NULL != job->rendered_dma_fence)
597 mali_dma_fence_signal_and_put(&job->rendered_dma_fence);
601 #if defined(CONFIG_MALI_DVFS)
602 if (mali_pp_job_is_window_surface(job)) {
603 struct mali_session_data *session;
604 session = mali_pp_job_get_session(job);
605 mali_session_inc_num_window_jobs(session);
608 _mali_osk_pm_dev_ref_put();
610 if (mali_utilization_enabled()) {
611 mali_utilization_pp_end();
613 mali_pm_record_gpu_idle(MALI_FALSE);
616 /* With ZRAM feature enabled, all pp jobs will be force to use deferred delete. */
617 mali_scheduler_deferred_pp_job_delete(job);
620 void mali_scheduler_abort_session(struct mali_session_data *session)
622 struct mali_gp_job *gp_job;
623 struct mali_gp_job *gp_tmp;
624 struct mali_pp_job *pp_job;
625 struct mali_pp_job *pp_tmp;
626 _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs_gp);
627 _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs_pp);
629 MALI_DEBUG_ASSERT_POINTER(session);
630 MALI_DEBUG_ASSERT(session->is_aborting);
632 MALI_DEBUG_PRINT(3, ("Mali scheduler: Aborting all queued jobs from session 0x%08X.\n",
635 mali_scheduler_lock();
637 /* Remove from GP normal priority queue */
638 _MALI_OSK_LIST_FOREACHENTRY(gp_job, gp_tmp, &job_queue_gp.normal_pri,
639 struct mali_gp_job, list) {
640 if (mali_gp_job_get_session(gp_job) == session) {
641 mali_gp_job_list_move(gp_job, &removed_jobs_gp);
642 job_queue_gp.depth--;
643 job_queue_gp.big_job_num -= gp_job->big_job ? 1 : 0;
647 /* Remove from GP high priority queue */
648 _MALI_OSK_LIST_FOREACHENTRY(gp_job, gp_tmp, &job_queue_gp.high_pri,
649 struct mali_gp_job, list) {
650 if (mali_gp_job_get_session(gp_job) == session) {
651 mali_gp_job_list_move(gp_job, &removed_jobs_gp);
652 job_queue_gp.depth--;
653 job_queue_gp.big_job_num -= gp_job->big_job ? 1 : 0;
657 /* Remove from PP normal priority queue */
658 _MALI_OSK_LIST_FOREACHENTRY(pp_job, pp_tmp,
659 &job_queue_pp.normal_pri,
660 struct mali_pp_job, list) {
661 if (mali_pp_job_get_session(pp_job) == session) {
662 mali_pp_job_fb_lookup_remove(pp_job);
664 job_queue_pp.depth -=
665 mali_pp_job_unstarted_sub_job_count(
667 mali_pp_job_mark_unstarted_failed(pp_job);
669 if (MALI_FALSE == mali_pp_job_has_unstarted_sub_jobs(pp_job)) {
670 if (mali_pp_job_is_complete(pp_job)) {
671 mali_pp_job_list_move(pp_job,
674 mali_pp_job_list_remove(pp_job);
680 /* Remove from PP high priority queue */
681 _MALI_OSK_LIST_FOREACHENTRY(pp_job, pp_tmp,
682 &job_queue_pp.high_pri,
683 struct mali_pp_job, list) {
684 if (mali_pp_job_get_session(pp_job) == session) {
685 mali_pp_job_fb_lookup_remove(pp_job);
687 job_queue_pp.depth -=
688 mali_pp_job_unstarted_sub_job_count(
690 mali_pp_job_mark_unstarted_failed(pp_job);
692 if (MALI_FALSE == mali_pp_job_has_unstarted_sub_jobs(pp_job)) {
693 if (mali_pp_job_is_complete(pp_job)) {
694 mali_pp_job_list_move(pp_job,
697 mali_pp_job_list_remove(pp_job);
704 * Release scheduler lock so we can release trackers
705 * (which will potentially queue new jobs)
707 mali_scheduler_unlock();
709 /* Release and complete all (non-running) found GP jobs */
710 _MALI_OSK_LIST_FOREACHENTRY(gp_job, gp_tmp, &removed_jobs_gp,
711 struct mali_gp_job, list) {
712 mali_timeline_tracker_release(mali_gp_job_get_tracker(gp_job));
713 mali_gp_job_signal_pp_tracker(gp_job, MALI_FALSE);
714 _mali_osk_list_delinit(&gp_job->list);
715 mali_scheduler_complete_gp_job(gp_job,
716 MALI_FALSE, MALI_FALSE, MALI_TRUE);
719 /* Release and complete non-running PP jobs */
720 _MALI_OSK_LIST_FOREACHENTRY(pp_job, pp_tmp, &removed_jobs_pp,
721 struct mali_pp_job, list) {
722 mali_timeline_tracker_release(mali_pp_job_get_tracker(pp_job));
723 _mali_osk_list_delinit(&pp_job->list);
724 mali_scheduler_complete_pp_job(pp_job, 0,
725 MALI_FALSE, MALI_TRUE);
729 _mali_osk_errcode_t _mali_ukk_gp_start_job(void *ctx,
730 _mali_uk_gp_start_job_s *uargs)
732 struct mali_session_data *session;
733 struct mali_gp_job *job;
734 mali_timeline_point point;
735 u32 __user *point_ptr = NULL;
737 MALI_DEBUG_ASSERT_POINTER(uargs);
738 MALI_DEBUG_ASSERT_POINTER(ctx);
740 session = (struct mali_session_data *)(uintptr_t)ctx;
742 job = mali_gp_job_create(session, uargs, mali_scheduler_get_new_id(),
745 MALI_PRINT_ERROR(("Failed to create GP job.\n"));
746 return _MALI_OSK_ERR_NOMEM;
749 point_ptr = (u32 __user *)(uintptr_t)mali_gp_job_get_timeline_point_ptr(job);
751 point = mali_scheduler_submit_gp_job(session, job);
753 if (0 != _mali_osk_put_user(((u32) point), point_ptr)) {
755 * Let user space know that something failed
756 * after the job was started.
758 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
761 return _MALI_OSK_ERR_OK;
764 _mali_osk_errcode_t _mali_ukk_pp_start_job(void *ctx,
765 _mali_uk_pp_start_job_s *uargs)
767 _mali_osk_errcode_t ret;
768 struct mali_session_data *session;
769 struct mali_pp_job *job;
770 mali_timeline_point point;
771 u32 __user *point_ptr = NULL;
773 MALI_DEBUG_ASSERT_POINTER(uargs);
774 MALI_DEBUG_ASSERT_POINTER(ctx);
776 session = (struct mali_session_data *)(uintptr_t)ctx;
778 job = mali_pp_job_create(session, uargs, mali_scheduler_get_new_id());
780 MALI_PRINT_ERROR(("Failed to create PP job.\n"));
781 return _MALI_OSK_ERR_NOMEM;
784 point_ptr = (u32 __user *)(uintptr_t)mali_pp_job_get_timeline_point_ptr(job);
787 ret = mali_scheduler_submit_pp_job(session, job, &point);
790 if (_MALI_OSK_ERR_OK == ret) {
791 if (0 != _mali_osk_put_user(((u32) point), point_ptr)) {
793 * Let user space know that something failed
794 * after the jobs were started.
796 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
803 _mali_osk_errcode_t _mali_ukk_pp_and_gp_start_job(void *ctx,
804 _mali_uk_pp_and_gp_start_job_s *uargs)
806 _mali_osk_errcode_t ret;
807 struct mali_session_data *session;
808 _mali_uk_pp_and_gp_start_job_s kargs;
809 struct mali_pp_job *pp_job;
810 struct mali_gp_job *gp_job;
811 u32 __user *point_ptr = NULL;
812 mali_timeline_point point;
813 _mali_uk_pp_start_job_s __user *pp_args;
814 _mali_uk_gp_start_job_s __user *gp_args;
816 MALI_DEBUG_ASSERT_POINTER(ctx);
817 MALI_DEBUG_ASSERT_POINTER(uargs);
819 session = (struct mali_session_data *) ctx;
821 if (0 != _mali_osk_copy_from_user(&kargs, uargs,
822 sizeof(_mali_uk_pp_and_gp_start_job_s))) {
823 return _MALI_OSK_ERR_NOMEM;
826 pp_args = (_mali_uk_pp_start_job_s __user *)(uintptr_t)kargs.pp_args;
827 gp_args = (_mali_uk_gp_start_job_s __user *)(uintptr_t)kargs.gp_args;
829 pp_job = mali_pp_job_create(session, pp_args,
830 mali_scheduler_get_new_id());
831 if (NULL == pp_job) {
832 MALI_PRINT_ERROR(("Failed to create PP job.\n"));
833 return _MALI_OSK_ERR_NOMEM;
836 gp_job = mali_gp_job_create(session, gp_args,
837 mali_scheduler_get_new_id(),
838 mali_pp_job_get_tracker(pp_job));
839 if (NULL == gp_job) {
840 MALI_PRINT_ERROR(("Failed to create GP job.\n"));
841 mali_pp_job_delete(pp_job);
842 return _MALI_OSK_ERR_NOMEM;
845 point_ptr = (u32 __user *)(uintptr_t)mali_pp_job_get_timeline_point_ptr(pp_job);
848 mali_scheduler_submit_gp_job(session, gp_job);
852 ret = mali_scheduler_submit_pp_job(session, pp_job, &point);
855 if (_MALI_OSK_ERR_OK == ret) {
856 if (0 != _mali_osk_put_user(((u32) point), point_ptr)) {
858 * Let user space know that something failed
859 * after the jobs were started.
861 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
868 void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args)
870 struct mali_session_data *session;
871 struct mali_pp_job *job;
872 struct mali_pp_job *tmp;
875 MALI_DEBUG_ASSERT_POINTER(args);
876 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
878 session = (struct mali_session_data *)(uintptr_t)args->ctx;
880 fb_lookup_id = args->fb_id & MALI_PP_JOB_FB_LOOKUP_LIST_MASK;
882 mali_scheduler_lock();
884 /* Iterate over all jobs for given frame builder_id. */
885 _MALI_OSK_LIST_FOREACHENTRY(job, tmp,
886 &session->pp_job_fb_lookup_list[fb_lookup_id],
887 struct mali_pp_job, session_fb_lookup_list) {
888 MALI_DEBUG_CODE(u32 disable_mask = 0);
890 if (mali_pp_job_get_frame_builder_id(job) !=
892 MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Disable WB mismatching FB.\n"));
896 MALI_DEBUG_CODE(disable_mask |= 0xD << (4 * 3));
898 if (mali_pp_job_get_wb0_source_addr(job) == args->wb0_memory) {
899 MALI_DEBUG_CODE(disable_mask |= 0x1 << (4 * 1));
900 mali_pp_job_disable_wb0(job);
903 if (mali_pp_job_get_wb1_source_addr(job) == args->wb1_memory) {
904 MALI_DEBUG_CODE(disable_mask |= 0x2 << (4 * 2));
905 mali_pp_job_disable_wb1(job);
908 if (mali_pp_job_get_wb2_source_addr(job) == args->wb2_memory) {
909 MALI_DEBUG_CODE(disable_mask |= 0x3 << (4 * 3));
910 mali_pp_job_disable_wb2(job);
912 MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disable WB: 0x%X.\n",
916 mali_scheduler_unlock();
919 #if MALI_STATE_TRACKING
920 u32 mali_scheduler_dump_state(char *buf, u32 size)
924 n += _mali_osk_snprintf(buf + n, size - n, "GP queues\n");
925 n += _mali_osk_snprintf(buf + n, size - n,
926 "\tQueue depth: %u\n", job_queue_gp.depth);
927 n += _mali_osk_snprintf(buf + n, size - n,
928 "\tNormal priority queue is %s\n",
929 _mali_osk_list_empty(&job_queue_gp.normal_pri) ?
930 "empty" : "not empty");
931 n += _mali_osk_snprintf(buf + n, size - n,
932 "\tHigh priority queue is %s\n",
933 _mali_osk_list_empty(&job_queue_gp.high_pri) ?
934 "empty" : "not empty");
936 n += _mali_osk_snprintf(buf + n, size - n,
938 n += _mali_osk_snprintf(buf + n, size - n,
939 "\tQueue depth: %u\n", job_queue_pp.depth);
940 n += _mali_osk_snprintf(buf + n, size - n,
941 "\tNormal priority queue is %s\n",
942 _mali_osk_list_empty(&job_queue_pp.normal_pri)
943 ? "empty" : "not empty");
944 n += _mali_osk_snprintf(buf + n, size - n,
945 "\tHigh priority queue is %s\n",
946 _mali_osk_list_empty(&job_queue_pp.high_pri)
947 ? "empty" : "not empty");
949 n += _mali_osk_snprintf(buf + n, size - n, "\n");
956 * ---------- Implementation of static functions ----------
959 static mali_timeline_point mali_scheduler_submit_gp_job(
960 struct mali_session_data *session, struct mali_gp_job *job)
962 mali_timeline_point point;
964 MALI_DEBUG_ASSERT_POINTER(session);
965 MALI_DEBUG_ASSERT_POINTER(job);
967 /* Add job to Timeline system. */
968 point = mali_timeline_system_add_tracker(session->timeline_system,
969 mali_gp_job_get_tracker(job), MALI_TIMELINE_GP);
974 static _mali_osk_errcode_t mali_scheduler_submit_pp_job(
975 struct mali_session_data *session, struct mali_pp_job *job, mali_timeline_point *point)
978 _mali_osk_errcode_t ret = _MALI_OSK_ERR_OK;
980 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
981 struct ww_acquire_ctx ww_actx;
983 u32 num_memory_cookies = 0;
984 struct reservation_object **reservation_object_list = NULL;
985 unsigned int num_reservation_object = 0;
988 MALI_DEBUG_ASSERT_POINTER(session);
989 MALI_DEBUG_ASSERT_POINTER(job);
991 mali_scheduler_lock();
993 * Adding job to the lookup list used to quickly discard
994 * writeback units of queued jobs.
996 mali_pp_job_fb_lookup_add(job);
997 mali_scheduler_unlock();
999 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
1001 /* Allocate the reservation_object_list to list the dma reservation object of dependent dma buffer */
1002 num_memory_cookies = mali_pp_job_num_memory_cookies(job);
1003 if (0 < num_memory_cookies) {
1004 reservation_object_list = kzalloc(sizeof(struct reservation_object *) * num_memory_cookies, GFP_KERNEL);
1005 if (NULL == reservation_object_list) {
1006 MALI_PRINT_ERROR(("Failed to alloc the reservation object list.\n"));
1007 ret = _MALI_OSK_ERR_NOMEM;
1008 goto failed_to_alloc_reservation_object_list;
1012 /* Add the dma reservation object into reservation_object_list*/
1013 for (i = 0; i < num_memory_cookies; i++) {
1014 mali_mem_backend *mem_backend = NULL;
1015 struct reservation_object *tmp_reservation_object = NULL;
1016 u32 mali_addr = mali_pp_job_get_memory_cookie(job, i);
1018 mem_backend = mali_mem_backend_struct_search(session, mali_addr);
1020 MALI_DEBUG_ASSERT_POINTER(mem_backend);
1022 if (NULL == mem_backend) {
1023 MALI_PRINT_ERROR(("Failed to find the memory backend for memory cookie[%d].\n", i));
1024 goto failed_to_find_mem_backend;
1027 if (MALI_MEM_DMA_BUF != mem_backend->type)
1030 tmp_reservation_object = mem_backend->dma_buf.attachment->buf->resv;
1032 if (NULL != tmp_reservation_object) {
1033 mali_dma_fence_add_reservation_object_list(tmp_reservation_object,
1034 reservation_object_list, &num_reservation_object);
1039 * Add the mali dma fence callback to wait for all dependent dma buf,
1040 * and extend the timeline system to support dma fence,
1041 * then create the new internal dma fence to replace all last dma fence for dependent dma buf.
1043 if (0 < num_reservation_object) {
1045 int num_dma_fence_waiter = 0;
1046 /* Create one new dma fence.*/
1047 job->rendered_dma_fence = mali_dma_fence_new(job->session->fence_context,
1048 _mali_osk_atomic_inc_return(&job->session->fence_seqno));
1050 if (NULL == job->rendered_dma_fence) {
1051 MALI_PRINT_ERROR(("Failed to creat one new dma fence.\n"));
1052 ret = _MALI_OSK_ERR_FAULT;
1053 goto failed_to_create_dma_fence;
1056 /* In order to avoid deadlock, wait/wound mutex lock to lock all dma buffers*/
1058 error = mali_dma_fence_lock_reservation_object_list(reservation_object_list,
1059 num_reservation_object, &ww_actx);
1062 MALI_PRINT_ERROR(("Failed to lock all reservation objects.\n"));
1063 ret = _MALI_OSK_ERR_FAULT;
1064 goto failed_to_lock_reservation_object_list;
1067 mali_dma_fence_context_init(&job->dma_fence_context,
1068 mali_timeline_dma_fence_callback, (void *)job);
1070 /* Add dma fence waiters and dma fence callback. */
1071 for (i = 0; i < num_reservation_object; i++) {
1072 ret = mali_dma_fence_context_add_waiters(&job->dma_fence_context, reservation_object_list[i]);
1073 if (_MALI_OSK_ERR_OK != ret) {
1074 MALI_PRINT_ERROR(("Failed to add waiter into mali dma fence context.\n"));
1075 goto failed_to_add_dma_fence_waiter;
1079 for (i = 0; i < num_reservation_object; i++) {
1080 reservation_object_add_excl_fence(reservation_object_list[i], job->rendered_dma_fence);
1083 num_dma_fence_waiter = job->dma_fence_context.num_dma_fence_waiter;
1085 /* Add job to Timeline system. */
1086 (*point) = mali_timeline_system_add_tracker(session->timeline_system,
1087 mali_pp_job_get_tracker(job), MALI_TIMELINE_PP);
1089 if (0 != num_dma_fence_waiter) {
1090 mali_dma_fence_context_dec_count(&job->dma_fence_context);
1093 /* Unlock all wait/wound mutex lock. */
1094 mali_dma_fence_unlock_reservation_object_list(reservation_object_list,
1095 num_reservation_object, &ww_actx);
1097 /* Add job to Timeline system. */
1098 (*point) = mali_timeline_system_add_tracker(session->timeline_system,
1099 mali_pp_job_get_tracker(job), MALI_TIMELINE_PP);
1102 kfree(reservation_object_list);
1105 /* Add job to Timeline system. */
1106 (*point) = mali_timeline_system_add_tracker(session->timeline_system,
1107 mali_pp_job_get_tracker(job), MALI_TIMELINE_PP);
1110 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
1111 failed_to_add_dma_fence_waiter:
1112 mali_dma_fence_context_term(&job->dma_fence_context);
1113 mali_dma_fence_unlock_reservation_object_list(reservation_object_list,
1114 num_reservation_object, &ww_actx);
1115 failed_to_lock_reservation_object_list:
1116 mali_dma_fence_signal_and_put(&job->rendered_dma_fence);
1117 failed_to_create_dma_fence:
1118 failed_to_find_mem_backend:
1119 if (NULL != reservation_object_list)
1120 kfree(reservation_object_list);
1121 failed_to_alloc_reservation_object_list:
1122 mali_pp_job_fb_lookup_remove(job);
1127 static mali_bool mali_scheduler_queue_gp_job(struct mali_gp_job *job)
1129 struct mali_session_data *session;
1130 _mali_osk_list_t *queue;
1132 MALI_DEBUG_ASSERT_SCHEDULER_LOCK_HELD();
1133 MALI_DEBUG_ASSERT_POINTER(job);
1135 session = mali_gp_job_get_session(job);
1136 MALI_DEBUG_ASSERT_POINTER(session);
1138 if (unlikely(session->is_aborting)) {
1139 MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Job %u (0x%08X) queued while session is aborting.\n",
1140 mali_gp_job_get_id(job), job));
1141 return MALI_FALSE; /* job not queued */
1144 mali_gp_job_set_cache_order(job, mali_scheduler_get_new_cache_order());
1146 /* Determine which queue the job should be added to. */
1147 if (session->use_high_priority_job_queue) {
1148 queue = &job_queue_gp.high_pri;
1150 queue = &job_queue_gp.normal_pri;
1153 job_queue_gp.depth += 1;
1154 job_queue_gp.big_job_num += (job->big_job) ? 1 : 0;
1156 /* Add job to queue (mali_gp_job_queue_add find correct place). */
1157 mali_gp_job_list_add(job, queue);
1160 * We hold a PM reference for every job we hold queued (and running)
1161 * It is important that we take this reference after job has been
1162 * added the the queue so that any runtime resume could schedule this
1163 * job right there and then.
1165 _mali_osk_pm_dev_ref_get_async();
1167 if (mali_utilization_enabled()) {
1169 * We cheat a little bit by counting the GP as busy from the
1170 * time a GP job is queued. This will be fine because we only
1171 * loose the tiny idle gap between jobs, but we will instead
1172 * get less utilization work to do (less locks taken)
1174 mali_utilization_gp_start();
1177 mali_pm_record_gpu_active(MALI_TRUE);
1179 /* Add profiling events for job enqueued */
1180 _mali_osk_profiling_add_event(
1181 MALI_PROFILING_EVENT_TYPE_SINGLE |
1182 MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
1183 MALI_PROFILING_EVENT_REASON_SINGLE_SW_GP_ENQUEUE,
1184 mali_gp_job_get_pid(job),
1185 mali_gp_job_get_tid(job),
1186 mali_gp_job_get_frame_builder_id(job),
1187 mali_gp_job_get_flush_id(job),
1190 #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
1191 trace_gpu_job_enqueue(mali_gp_job_get_tid(job),
1192 mali_gp_job_get_id(job), "GP");
1195 MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n",
1196 mali_gp_job_get_id(job), job));
1198 return MALI_TRUE; /* job queued */
1201 static mali_bool mali_scheduler_queue_pp_job(struct mali_pp_job *job)
1203 struct mali_session_data *session;
1204 _mali_osk_list_t *queue = NULL;
1206 MALI_DEBUG_ASSERT_SCHEDULER_LOCK_HELD();
1207 MALI_DEBUG_ASSERT_POINTER(job);
1209 session = mali_pp_job_get_session(job);
1210 MALI_DEBUG_ASSERT_POINTER(session);
1212 if (unlikely(session->is_aborting)) {
1213 MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) queued while session is aborting.\n",
1214 mali_pp_job_get_id(job), job));
1215 return MALI_FALSE; /* job not queued */
1216 } else if (unlikely(MALI_SWAP_IN_FAIL == job->swap_status)) {
1217 MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) queued while swap in failed.\n",
1218 mali_pp_job_get_id(job), job));
1222 mali_pp_job_set_cache_order(job, mali_scheduler_get_new_cache_order());
1224 if (session->use_high_priority_job_queue) {
1225 queue = &job_queue_pp.high_pri;
1227 queue = &job_queue_pp.normal_pri;
1230 job_queue_pp.depth +=
1231 mali_pp_job_get_sub_job_count(job);
1233 /* Add job to queue (mali_gp_job_queue_add find correct place). */
1234 mali_pp_job_list_add(job, queue);
1237 * We hold a PM reference for every job we hold queued (and running)
1238 * It is important that we take this reference after job has been
1239 * added the the queue so that any runtime resume could schedule this
1240 * job right there and then.
1242 _mali_osk_pm_dev_ref_get_async();
1244 if (mali_utilization_enabled()) {
1246 * We cheat a little bit by counting the PP as busy from the
1247 * time a PP job is queued. This will be fine because we only
1248 * loose the tiny idle gap between jobs, but we will instead
1249 * get less utilization work to do (less locks taken)
1251 mali_utilization_pp_start();
1254 mali_pm_record_gpu_active(MALI_FALSE);
1256 /* Add profiling events for job enqueued */
1257 _mali_osk_profiling_add_event(
1258 MALI_PROFILING_EVENT_TYPE_SINGLE |
1259 MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
1260 MALI_PROFILING_EVENT_REASON_SINGLE_SW_PP_ENQUEUE,
1261 mali_pp_job_get_pid(job),
1262 mali_pp_job_get_tid(job),
1263 mali_pp_job_get_frame_builder_id(job),
1264 mali_pp_job_get_flush_id(job),
1267 #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
1268 trace_gpu_job_enqueue(mali_pp_job_get_tid(job),
1269 mali_pp_job_get_id(job), "PP");
1272 MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) with %u parts queued.\n",
1273 mali_pp_job_is_virtual(job)
1274 ? "Virtual" : "Physical",
1275 mali_pp_job_get_id(job), job,
1276 mali_pp_job_get_sub_job_count(job)));
1278 return MALI_TRUE; /* job queued */
1281 static void mali_scheduler_return_gp_job_to_user(struct mali_gp_job *job,
1284 _mali_uk_gp_job_finished_s *jobres;
1285 struct mali_session_data *session;
1286 _mali_osk_notification_t *notification;
1288 MALI_DEBUG_ASSERT_POINTER(job);
1290 session = mali_gp_job_get_session(job);
1291 MALI_DEBUG_ASSERT_POINTER(session);
1293 notification = mali_gp_job_get_finished_notification(job);
1294 MALI_DEBUG_ASSERT_POINTER(notification);
1296 jobres = notification->result_buffer;
1297 MALI_DEBUG_ASSERT_POINTER(jobres);
1299 jobres->pending_big_job_num = mali_scheduler_job_gp_big_job_count();
1301 jobres->user_job_ptr = mali_gp_job_get_user_id(job);
1302 if (MALI_TRUE == success) {
1303 jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
1305 jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
1307 jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job);
1308 jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job);
1309 jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job);
1311 mali_session_send_notification(session, notification);
1314 void mali_scheduler_return_pp_job_to_user(struct mali_pp_job *job,
1315 u32 num_cores_in_virtual)
1318 u32 num_counters_to_copy;
1319 _mali_uk_pp_job_finished_s *jobres;
1320 struct mali_session_data *session;
1321 _mali_osk_notification_t *notification;
1323 if (MALI_TRUE == mali_pp_job_use_no_notification(job)) {
1327 MALI_DEBUG_ASSERT_POINTER(job);
1329 session = mali_pp_job_get_session(job);
1330 MALI_DEBUG_ASSERT_POINTER(session);
1332 notification = mali_pp_job_get_finished_notification(job);
1333 MALI_DEBUG_ASSERT_POINTER(notification);
1335 jobres = notification->result_buffer;
1336 MALI_DEBUG_ASSERT_POINTER(jobres);
1338 jobres->user_job_ptr = mali_pp_job_get_user_id(job);
1339 if (MALI_TRUE == mali_pp_job_was_success(job)) {
1340 jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
1342 jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
1345 if (mali_pp_job_is_virtual(job)) {
1346 num_counters_to_copy = num_cores_in_virtual;
1348 num_counters_to_copy = mali_pp_job_get_sub_job_count(job);
1351 for (i = 0; i < num_counters_to_copy; i++) {
1352 jobres->perf_counter0[i] =
1353 mali_pp_job_get_perf_counter_value0(job, i);
1354 jobres->perf_counter1[i] =
1355 mali_pp_job_get_perf_counter_value1(job, i);
1356 jobres->perf_counter_src0 =
1357 mali_pp_job_get_pp_counter_global_src0();
1358 jobres->perf_counter_src1 =
1359 mali_pp_job_get_pp_counter_global_src1();
1362 mali_session_send_notification(session, notification);
1365 static void mali_scheduler_deferred_pp_job_delete(struct mali_pp_job *job)
1367 MALI_DEBUG_ASSERT_POINTER(job);
1369 _mali_osk_spinlock_irq_lock(scheduler_pp_job_delete_lock);
1370 mali_pp_job_list_addtail(job, &scheduler_pp_job_deletion_queue);
1371 _mali_osk_spinlock_irq_unlock(scheduler_pp_job_delete_lock);
1373 _mali_osk_wq_schedule_work(scheduler_wq_pp_job_delete);
1376 void mali_scheduler_do_pp_job_delete(void *arg)
1378 _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
1379 struct mali_pp_job *job;
1380 struct mali_pp_job *tmp;
1385 * Quickly "unhook" the jobs pending to be deleted, so we can release
1386 * the lock before we start deleting the job objects
1387 * (without any locks held)
1389 _mali_osk_spinlock_irq_lock(scheduler_pp_job_delete_lock);
1390 _mali_osk_list_move_list(&scheduler_pp_job_deletion_queue, &list);
1391 _mali_osk_spinlock_irq_unlock(scheduler_pp_job_delete_lock);
1393 _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list,
1394 struct mali_pp_job, list) {
1395 _mali_osk_list_delinit(&job->list);
1397 #if defined(CONFIG_MALI_DMA_BUF_FENCE)
1398 mali_dma_fence_context_term(&job->dma_fence_context);
1401 mali_pp_job_delete(job); /* delete the job object itself */
1405 #if defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE)
1407 static void mali_scheduler_deferred_pp_job_queue(struct mali_pp_job *job)
1409 MALI_DEBUG_ASSERT_POINTER(job);
1411 _mali_osk_spinlock_irq_lock(scheduler_pp_job_queue_lock);
1412 mali_pp_job_list_addtail(job, &scheduler_pp_job_queue_list);
1413 _mali_osk_spinlock_irq_unlock(scheduler_pp_job_queue_lock);
1415 _mali_osk_wq_schedule_work(scheduler_wq_pp_job_queue);
1418 static void mali_scheduler_do_pp_job_queue(void *arg)
1420 _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
1421 struct mali_pp_job *job;
1422 struct mali_pp_job *tmp;
1423 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
1428 * Quickly "unhook" the jobs pending to be queued, so we can release
1429 * the lock before we start queueing the job objects
1430 * (without any locks held)
1432 _mali_osk_spinlock_irq_lock(scheduler_pp_job_queue_lock);
1433 _mali_osk_list_move_list(&scheduler_pp_job_queue_list, &list);
1434 _mali_osk_spinlock_irq_unlock(scheduler_pp_job_queue_lock);
1436 /* First loop through all jobs and do the pre-work (no locks needed) */
1437 _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list,
1438 struct mali_pp_job, list) {
1439 if (mali_pp_job_needs_dma_buf_mapping(job)) {
1441 * This operation could fail, but we continue anyway,
1442 * because the worst that could happen is that this
1443 * job will fail due to a Mali page fault.
1445 mali_dma_buf_map_job(job);
1449 mali_scheduler_lock();
1451 /* Then loop through all jobs again to queue them (lock needed) */
1452 _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list,
1453 struct mali_pp_job, list) {
1455 /* Remove from scheduler_pp_job_queue_list before queueing */
1456 mali_pp_job_list_remove(job);
1458 if (mali_scheduler_queue_pp_job(job)) {
1459 /* Job queued successfully */
1460 schedule_mask |= MALI_SCHEDULER_MASK_PP;
1462 /* Failed to enqueue job, release job (with error) */
1463 mali_pp_job_fb_lookup_remove(job);
1464 mali_pp_job_mark_unstarted_failed(job);
1466 /* unlock scheduler in this uncommon case */
1467 mali_scheduler_unlock();
1469 schedule_mask |= mali_timeline_tracker_release(
1470 mali_pp_job_get_tracker(job));
1472 /* Notify user space and close the job object */
1473 mali_scheduler_complete_pp_job(job, 0, MALI_TRUE,
1476 mali_scheduler_lock();
1480 mali_scheduler_unlock();
1482 /* Trigger scheduling of jobs */
1483 mali_executor_schedule_from_mask(schedule_mask, MALI_FALSE);
1486 #endif /* defined(MALI_SCHEDULER_USE_DEFERRED_PP_JOB_QUEUE) */
1488 void mali_scheduler_gp_pp_job_queue_print(void)
1490 struct mali_gp_job *gp_job = NULL;
1491 struct mali_gp_job *tmp_gp_job = NULL;
1492 struct mali_pp_job *pp_job = NULL;
1493 struct mali_pp_job *tmp_pp_job = NULL;
1495 MALI_DEBUG_ASSERT_LOCK_HELD(mali_scheduler_lock_obj);
1496 MALI_DEBUG_ASSERT_LOCK_HELD(mali_executor_lock_obj);
1498 /* dump job queup status */
1499 if ((0 == job_queue_gp.depth) && (0 == job_queue_pp.depth)) {
1500 MALI_PRINT(("No GP&PP job in the job queue.\n"));
1504 MALI_PRINT(("Total (%d) GP job in the job queue.\n", job_queue_gp.depth));
1505 if (job_queue_gp.depth > 0) {
1506 if (!_mali_osk_list_empty(&job_queue_gp.high_pri)) {
1507 _MALI_OSK_LIST_FOREACHENTRY(gp_job, tmp_gp_job, &job_queue_gp.high_pri,
1508 struct mali_gp_job, list) {
1509 MALI_PRINT(("GP job(%p) id = %d tid = %d pid = %d in the gp job high_pri queue\n", gp_job, gp_job->id, gp_job->tid, gp_job->pid));
1513 if (!_mali_osk_list_empty(&job_queue_gp.normal_pri)) {
1514 _MALI_OSK_LIST_FOREACHENTRY(gp_job, tmp_gp_job, &job_queue_gp.normal_pri,
1515 struct mali_gp_job, list) {
1516 MALI_PRINT(("GP job(%p) id = %d tid = %d pid = %d in the gp job normal_pri queue\n", gp_job, gp_job->id, gp_job->tid, gp_job->pid));
1521 MALI_PRINT(("Total (%d) PP job in the job queue.\n", job_queue_pp.depth));
1522 if (job_queue_pp.depth > 0) {
1523 if (!_mali_osk_list_empty(&job_queue_pp.high_pri)) {
1524 _MALI_OSK_LIST_FOREACHENTRY(pp_job, tmp_pp_job, &job_queue_pp.high_pri,
1525 struct mali_pp_job, list) {
1526 if (mali_pp_job_is_virtual(pp_job)) {
1527 MALI_PRINT(("PP Virtual job(%p) id = %d tid = %d pid = %d in the pp job high_pri queue\n", pp_job, pp_job->id, pp_job->tid, pp_job->pid));
1529 MALI_PRINT(("PP Physical job(%p) id = %d tid = %d pid = %d in the pp job high_pri queue\n", pp_job, pp_job->id, pp_job->tid, pp_job->pid));
1534 if (!_mali_osk_list_empty(&job_queue_pp.normal_pri)) {
1535 _MALI_OSK_LIST_FOREACHENTRY(pp_job, tmp_pp_job, &job_queue_pp.normal_pri,
1536 struct mali_pp_job, list) {
1537 if (mali_pp_job_is_virtual(pp_job)) {
1538 MALI_PRINT(("PP Virtual job(%p) id = %d tid = %d pid = %d in the pp job normal_pri queue\n", pp_job, pp_job->id, pp_job->tid, pp_job->pid));
1540 MALI_PRINT(("PP Physical job(%p) id = %d tid = %d pid = %d in the pp job normal_pri queue\n", pp_job, pp_job->id, pp_job->tid, pp_job->pid));
1546 /* dump group running job status */
1547 mali_executor_running_status_print();