2 * Copyright (C) 2012-2014 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_executor.h"
12 #include "mali_scheduler.h"
13 #include "mali_kernel_common.h"
14 #include "mali_kernel_core.h"
16 #include "mali_osk_list.h"
18 #include "mali_pp_job.h"
19 #include "mali_group.h"
21 #include "mali_timeline.h"
22 #include "mali_osk_profiling.h"
23 #include "mali_session.h"
25 /*Add for voltage scan function*/
26 extern u32 mali_group_error;
29 * If dma_buf with map on demand is used, we defer job deletion and job queue
30 * if in atomic context, since both might sleep.
32 #if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
33 #define MALI_EXECUTOR_USE_DEFERRED_PP_JOB_DELETE 1
34 #define MALI_EXECUTOR_USE_DEFERRED_PP_JOB_QUEUE 1
35 #endif /* !defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) */
38 * ---------- static type definitions (structs, enums, etc) ----------
41 enum mali_executor_state_t {
42 EXEC_STATE_NOT_PRESENT, /* Virtual group on Mali-300/400 (do not use) */
43 EXEC_STATE_DISABLED, /* Disabled by core scaling (do not use) */
44 EXEC_STATE_EMPTY, /* No child groups for virtual group (do not use) */
45 EXEC_STATE_INACTIVE, /* Can be used, but must be activate first */
46 EXEC_STATE_IDLE, /* Active and ready to be used */
47 EXEC_STATE_WORKING, /* Executing a job */
51 * ---------- global variables (exported due to inline functions) ----------
54 /* Lock for this module (protecting all HW access except L2 caches) */
55 _mali_osk_spinlock_irq_t *mali_executor_lock_obj = NULL;
57 mali_bool mali_executor_hints[MALI_EXECUTOR_HINT_MAX];
60 * ---------- static variables ----------
63 /* Used to defer job scheduling */
64 static _mali_osk_wq_work_t *executor_wq_high_pri = NULL;
66 /* Store version from GP and PP (user space wants to know this) */
67 static u32 pp_version = 0;
68 static u32 gp_version = 0;
70 /* List of physical PP groups which are disabled by some external source */
71 static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_disabled);
72 static u32 group_list_disabled_count = 0;
74 /* List of groups which can be used, but activate first */
75 static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_inactive);
76 static u32 group_list_inactive_count = 0;
78 /* List of groups which are active and ready to be used */
79 static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_idle);
80 static u32 group_list_idle_count = 0;
82 /* List of groups which are executing a job */
83 static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_working);
84 static u32 group_list_working_count = 0;
86 /* Virtual group (if any) */
87 static struct mali_group *virtual_group = NULL;
89 /* Virtual group state is tracked with a state variable instead of 4 lists */
90 static enum mali_executor_state_t virtual_group_state = EXEC_STATE_NOT_PRESENT;
93 static struct mali_group *gp_group = NULL;
95 /* GP group state is tracked with a state variable instead of 4 lists */
96 static enum mali_executor_state_t gp_group_state = EXEC_STATE_NOT_PRESENT;
98 static u32 gp_returned_cookie = 0;
100 /* Total number of physical PP cores present */
101 static u32 num_physical_pp_cores_total = 0;
103 /* Number of physical cores which are enabled */
104 static u32 num_physical_pp_cores_enabled = 0;
106 /* Enable or disable core scaling */
107 static mali_bool core_scaling_enabled = MALI_TRUE;
109 /* Variables to allow safe pausing of the scheduler */
110 static _mali_osk_wait_queue_t *executor_working_wait_queue = NULL;
111 static u32 pause_count = 0;
113 /* PP cores haven't been enabled because of some pp cores haven't been disabled. */
114 static int core_scaling_delay_up_mask[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
116 /* Variables used to implement notify pp core changes to userspace when core scaling
117 * is finished in mali_executor_complete_group() function. */
118 static _mali_osk_wq_work_t *executor_wq_notify_core_change = NULL;
119 static _mali_osk_wait_queue_t *executor_notify_core_change_wait_queue = NULL;
122 * ---------- Forward declaration of static functions ----------
124 static void mali_executor_lock(void);
125 static void mali_executor_unlock(void);
126 static mali_bool mali_executor_is_suspended(void *data);
127 static mali_bool mali_executor_is_working(void);
128 static void mali_executor_disable_empty_virtual(void);
129 static mali_bool mali_executor_physical_rejoin_virtual(struct mali_group *group);
130 static mali_bool mali_executor_has_virtual_group(void);
131 static mali_bool mali_executor_virtual_group_is_usable(void);
132 static void mali_executor_schedule(void);
133 static void mali_executor_wq_schedule(void *arg);
134 static void mali_executor_send_gp_oom_to_user(struct mali_gp_job *job);
135 static void mali_executor_complete_group(struct mali_group *group,
137 mali_bool release_jobs,
138 struct mali_gp_job **gp_job_done,
139 struct mali_pp_job **pp_job_done);
140 static void mali_executor_change_state_pp_physical(struct mali_group *group,
141 _mali_osk_list_t *old_list,
143 _mali_osk_list_t *new_list,
145 static mali_bool mali_executor_group_is_in_state(struct mali_group *group,
146 enum mali_executor_state_t state);
148 static void mali_executor_group_enable_internal(struct mali_group *group);
149 static void mali_executor_group_disable_internal(struct mali_group *group);
150 static void mali_executor_core_scale(unsigned int target_core_nr);
151 static void mali_executor_core_scale_in_group_complete(struct mali_group *group);
152 static void mali_executor_notify_core_change(u32 num_cores);
153 static void mali_executor_wq_notify_core_change(void *arg);
154 static void mali_executor_change_group_status_disabled(struct mali_group *group);
155 static mali_bool mali_executor_deactivate_list_idle(mali_bool deactivate_idle_group);
156 static void mali_executor_set_state_pp_physical(struct mali_group *group,
157 _mali_osk_list_t *new_list,
161 * ---------- Actual implementation ----------
164 _mali_osk_errcode_t mali_executor_initialize(void)
166 mali_executor_lock_obj = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_EXECUTOR);
167 if (NULL == mali_executor_lock_obj) {
168 mali_executor_terminate();
169 return _MALI_OSK_ERR_NOMEM;
172 executor_wq_high_pri = _mali_osk_wq_create_work_high_pri(mali_executor_wq_schedule, NULL);
173 if (NULL == executor_wq_high_pri) {
174 mali_executor_terminate();
175 return _MALI_OSK_ERR_NOMEM;
178 executor_working_wait_queue = _mali_osk_wait_queue_init();
179 if (NULL == executor_working_wait_queue) {
180 mali_executor_terminate();
181 return _MALI_OSK_ERR_NOMEM;
184 executor_wq_notify_core_change = _mali_osk_wq_create_work(mali_executor_wq_notify_core_change, NULL);
185 if (NULL == executor_wq_notify_core_change) {
186 mali_executor_terminate();
187 return _MALI_OSK_ERR_NOMEM;
190 executor_notify_core_change_wait_queue = _mali_osk_wait_queue_init();
191 if (NULL == executor_notify_core_change_wait_queue) {
192 mali_executor_terminate();
193 return _MALI_OSK_ERR_NOMEM;
196 return _MALI_OSK_ERR_OK;
199 void mali_executor_terminate(void)
201 if (NULL != executor_notify_core_change_wait_queue) {
202 _mali_osk_wait_queue_term(executor_notify_core_change_wait_queue);
203 executor_notify_core_change_wait_queue = NULL;
206 if (NULL != executor_wq_notify_core_change) {
207 _mali_osk_wq_delete_work(executor_wq_notify_core_change);
208 executor_wq_notify_core_change = NULL;
211 if (NULL != executor_working_wait_queue) {
212 _mali_osk_wait_queue_term(executor_working_wait_queue);
213 executor_working_wait_queue = NULL;
216 if (NULL != executor_wq_high_pri) {
217 _mali_osk_wq_delete_work(executor_wq_high_pri);
218 executor_wq_high_pri = NULL;
221 if (NULL != mali_executor_lock_obj) {
222 _mali_osk_spinlock_irq_term(mali_executor_lock_obj);
223 mali_executor_lock_obj = NULL;
227 void mali_executor_populate(void)
232 num_groups = mali_group_get_glob_num_groups();
234 /* Do we have a virtual group? */
235 for (i = 0; i < num_groups; i++) {
236 struct mali_group *group = mali_group_get_glob_group(i);
238 if (mali_group_is_virtual(group)) {
239 virtual_group = group;
240 virtual_group_state = EXEC_STATE_INACTIVE;
245 /* Find all the available physical GP and PP cores */
246 for (i = 0; i < num_groups; i++) {
247 struct mali_group *group = mali_group_get_glob_group(i);
250 struct mali_pp_core *pp_core = mali_group_get_pp_core(group);
251 struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
253 if (!mali_group_is_virtual(group)) {
254 if (NULL != pp_core) {
255 if (0 == pp_version) {
256 /* Retrieve PP version from the first available PP core */
257 pp_version = mali_pp_core_get_version(pp_core);
260 if (NULL != virtual_group) {
261 mali_executor_lock();
262 mali_group_add_group(virtual_group, group);
263 mali_executor_unlock();
265 _mali_osk_list_add(&group->executor_list, &group_list_inactive);
266 group_list_inactive_count++;
269 num_physical_pp_cores_total++;
271 MALI_DEBUG_ASSERT_POINTER(gp_core);
273 if (0 == gp_version) {
274 /* Retrieve GP version */
275 gp_version = mali_gp_core_get_version(gp_core);
279 gp_group_state = EXEC_STATE_INACTIVE;
286 num_physical_pp_cores_enabled = num_physical_pp_cores_total;
289 void mali_executor_depopulate(void)
291 struct mali_group *group;
292 struct mali_group *temp;
294 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != gp_group_state);
296 if (NULL != gp_group) {
297 mali_group_delete(gp_group);
301 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != virtual_group_state);
303 if (NULL != virtual_group) {
304 mali_group_delete(virtual_group);
305 virtual_group = NULL;
308 MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
310 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, executor_list) {
311 mali_group_delete(group);
314 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive, struct mali_group, executor_list) {
315 mali_group_delete(group);
318 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, executor_list) {
319 mali_group_delete(group);
323 void mali_executor_suspend(void)
325 mali_executor_lock();
327 /* Increment the pause_count so that no more jobs will be scheduled */
330 mali_executor_unlock();
332 _mali_osk_wait_queue_wait_event(executor_working_wait_queue,
333 mali_executor_is_suspended, NULL);
336 * mali_executor_complete_XX() leaves jobs in idle state.
337 * deactivate option is used when we are going to power down
338 * the entire GPU (OS suspend) and want a consistent SW vs HW
341 mali_executor_lock();
343 mali_executor_deactivate_list_idle(MALI_TRUE);
346 * The following steps are used to deactive all of activated
347 * (MALI_GROUP_STATE_ACTIVE) and activating (MALI_GROUP
348 * _STAET_ACTIVATION_PENDING) groups, to make sure the variable
349 * pd_mask_wanted is equal with 0. */
350 if (MALI_GROUP_STATE_INACTIVE != mali_group_get_state(gp_group)) {
351 gp_group_state = EXEC_STATE_INACTIVE;
352 mali_group_deactivate(gp_group);
355 if (mali_executor_has_virtual_group()) {
356 if (MALI_GROUP_STATE_INACTIVE
357 != mali_group_get_state(virtual_group)) {
358 virtual_group_state = EXEC_STATE_INACTIVE;
359 mali_group_deactivate(virtual_group);
363 if (0 < group_list_inactive_count) {
364 struct mali_group *group;
365 struct mali_group *temp;
367 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
368 &group_list_inactive,
369 struct mali_group, executor_list) {
370 if (MALI_GROUP_STATE_ACTIVATION_PENDING
371 == mali_group_get_state(group)) {
372 mali_group_deactivate(group);
376 * On mali-450 platform, we may have physical group in the group inactive
377 * list, and its state is MALI_GROUP_STATE_ACTIVATION_PENDING, so we only
378 * deactivate it is not enough, we still also need add it back to virtual group.
379 * And now, virtual group must be in INACTIVE state, so it's safe to add
380 * physical group to virtual group at this point.
382 if (NULL != virtual_group) {
383 _mali_osk_list_delinit(&group->executor_list);
384 group_list_inactive_count--;
386 mali_group_add_group(virtual_group, group);
391 mali_executor_unlock();
394 void mali_executor_resume(void)
396 mali_executor_lock();
398 /* Decrement pause_count to allow scheduling again (if it reaches 0) */
400 if (0 == pause_count) {
401 mali_executor_schedule();
404 mali_executor_unlock();
407 u32 mali_executor_get_num_cores_total(void)
409 return num_physical_pp_cores_total;
412 u32 mali_executor_get_num_cores_enabled(void)
414 return num_physical_pp_cores_enabled;
417 struct mali_pp_core *mali_executor_get_virtual_pp(void)
419 MALI_DEBUG_ASSERT_POINTER(virtual_group);
420 MALI_DEBUG_ASSERT_POINTER(virtual_group->pp_core);
421 return virtual_group->pp_core;
424 struct mali_group *mali_executor_get_virtual_group(void)
426 return virtual_group;
429 void mali_executor_zap_all_active(struct mali_session_data *session)
431 struct mali_group *group;
432 struct mali_group *temp;
435 mali_executor_lock();
438 * This function is a bit complicated because
439 * mali_group_zap_session() can fail. This only happens because the
440 * group is in an unhandled page fault status.
441 * We need to make sure this page fault is handled before we return,
442 * so that we know every single outstanding MMU transactions have
443 * completed. This will allow caller to safely remove physical pages
444 * when we have returned.
447 MALI_DEBUG_ASSERT(NULL != gp_group);
448 ret = mali_group_zap_session(gp_group, session);
449 if (MALI_FALSE == ret) {
450 struct mali_gp_job *gp_job = NULL;
452 mali_executor_complete_group(gp_group, MALI_FALSE,
453 MALI_TRUE, &gp_job, NULL);
455 MALI_DEBUG_ASSERT_POINTER(gp_job);
457 /* GP job completed, make sure it is freed */
458 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
459 MALI_TRUE, MALI_TRUE);
462 if (mali_executor_has_virtual_group()) {
463 ret = mali_group_zap_session(virtual_group, session);
464 if (MALI_FALSE == ret) {
465 struct mali_pp_job *pp_job = NULL;
467 mali_executor_complete_group(virtual_group, MALI_FALSE,
468 MALI_TRUE, NULL, &pp_job);
470 if (NULL != pp_job) {
471 /* PP job completed, make sure it is freed */
472 mali_scheduler_complete_pp_job(pp_job, 0,
473 MALI_FALSE, MALI_TRUE);
478 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working,
479 struct mali_group, executor_list) {
480 ret = mali_group_zap_session(group, session);
481 if (MALI_FALSE == ret) {
482 ret = mali_group_zap_session(group, session);
483 if (MALI_FALSE == ret) {
484 struct mali_pp_job *pp_job = NULL;
486 mali_executor_complete_group(group, MALI_FALSE,
487 MALI_TRUE, NULL, &pp_job);
489 if (NULL != pp_job) {
490 /* PP job completed, free it */
491 mali_scheduler_complete_pp_job(pp_job,
499 mali_executor_unlock();
502 void mali_executor_schedule_from_mask(mali_scheduler_mask mask, mali_bool deferred_schedule)
504 if (MALI_SCHEDULER_MASK_EMPTY != mask) {
505 if (MALI_TRUE == deferred_schedule) {
506 _mali_osk_wq_schedule_work_high_pri(executor_wq_high_pri);
508 /* Schedule from this thread*/
509 mali_executor_lock();
510 mali_executor_schedule();
511 mali_executor_unlock();
516 _mali_osk_errcode_t mali_executor_interrupt_gp(struct mali_group *group,
517 mali_bool in_upper_half)
519 enum mali_interrupt_result int_result;
520 mali_bool time_out = MALI_FALSE;
522 MALI_DEBUG_PRINT(4, ("Executor: GP interrupt from %s in %s half\n",
523 mali_group_core_description(group),
524 in_upper_half ? "upper" : "bottom"));
526 mali_executor_lock();
527 if (!mali_group_is_working(group)) {
528 /* Not working, so nothing to do */
529 mali_executor_unlock();
530 return _MALI_OSK_ERR_FAULT;
533 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
534 MALI_DEBUG_ASSERT(mali_group_is_working(group));
536 if (mali_group_has_timed_out(group)) {
537 int_result = MALI_INTERRUPT_RESULT_ERROR;
538 time_out = MALI_TRUE;
539 MALI_PRINT(("Executor GP: Job %d Timeout on %s\n",
540 mali_gp_job_get_id(group->gp_running_job),
541 mali_group_core_description(group)));
543 int_result = mali_group_get_interrupt_result_gp(group);
544 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
545 mali_executor_unlock();
546 return _MALI_OSK_ERR_FAULT;
550 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
551 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
552 /* No interrupts signalled, so nothing to do */
553 mali_executor_unlock();
554 return _MALI_OSK_ERR_FAULT;
557 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_NONE != int_result);
560 mali_group_mask_all_interrupts_gp(group);
562 if (MALI_INTERRUPT_RESULT_SUCCESS_VS == int_result) {
563 if (mali_group_gp_is_active(group)) {
564 /* Only VS completed so far, while PLBU is still active */
566 /* Enable all but the current interrupt */
567 mali_group_enable_interrupts_gp(group, int_result);
569 mali_executor_unlock();
570 return _MALI_OSK_ERR_OK;
572 } else if (MALI_INTERRUPT_RESULT_SUCCESS_PLBU == int_result) {
573 if (mali_group_gp_is_active(group)) {
574 /* Only PLBU completed so far, while VS is still active */
576 /* Enable all but the current interrupt */
577 mali_group_enable_interrupts_gp(group, int_result);
579 mali_executor_unlock();
580 return _MALI_OSK_ERR_OK;
582 } else if (MALI_INTERRUPT_RESULT_OOM == int_result) {
583 struct mali_gp_job *job = mali_group_get_running_gp_job(group);
585 /* PLBU out of mem */
586 MALI_DEBUG_PRINT(3, ("Executor: PLBU needs more heap memory\n"));
588 #if defined(CONFIG_MALI400_PROFILING)
589 /* Give group a chance to generate a SUSPEND event */
590 mali_group_oom(group);
594 * no need to hold interrupt raised while
595 * waiting for more memory.
597 mali_executor_send_gp_oom_to_user(job);
599 mali_executor_unlock();
601 return _MALI_OSK_ERR_OK;
604 /*Add for voltage scan function*/
605 if (MALI_INTERRUPT_RESULT_ERROR == int_result)
608 /* We should now have a real interrupt to handle */
610 MALI_DEBUG_PRINT(4, ("Executor: Group %s completed with %s\n",
611 mali_group_core_description(group),
612 (MALI_INTERRUPT_RESULT_ERROR == int_result) ?
613 "ERROR" : "success"));
615 if (in_upper_half && MALI_INTERRUPT_RESULT_ERROR == int_result) {
616 /* Don't bother to do processing of errors in upper half */
617 mali_executor_unlock();
619 if (MALI_FALSE == time_out) {
620 mali_group_schedule_bottom_half_gp(group);
623 struct mali_gp_job *job;
626 success = (int_result != MALI_INTERRUPT_RESULT_ERROR) ?
627 MALI_TRUE : MALI_FALSE;
629 mali_executor_complete_group(group, success,
630 MALI_TRUE, &job, NULL);
632 mali_executor_unlock();
634 /* GP jobs always fully complete */
635 MALI_DEBUG_ASSERT(NULL != job);
637 /* This will notify user space and close the job object */
638 mali_scheduler_complete_gp_job(job, success,
639 MALI_TRUE, MALI_TRUE);
642 return _MALI_OSK_ERR_OK;
645 _mali_osk_errcode_t mali_executor_interrupt_pp(struct mali_group *group,
646 mali_bool in_upper_half)
648 enum mali_interrupt_result int_result;
649 mali_bool time_out = MALI_FALSE;
651 MALI_DEBUG_PRINT(4, ("Executor: PP interrupt from %s in %s half\n",
652 mali_group_core_description(group),
653 in_upper_half ? "upper" : "bottom"));
655 mali_executor_lock();
657 if (!mali_group_is_working(group)) {
658 /* Not working, so nothing to do */
659 mali_executor_unlock();
660 return _MALI_OSK_ERR_FAULT;
664 if (mali_group_is_in_virtual(group)) {
665 /* Child groups should never handle PP interrupts */
666 MALI_DEBUG_ASSERT(!mali_group_has_timed_out(group));
667 mali_executor_unlock();
668 return _MALI_OSK_ERR_FAULT;
671 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
672 MALI_DEBUG_ASSERT(mali_group_is_working(group));
673 MALI_DEBUG_ASSERT(!mali_group_is_in_virtual(group));
675 if (mali_group_has_timed_out(group)) {
676 int_result = MALI_INTERRUPT_RESULT_ERROR;
677 time_out = MALI_TRUE;
678 MALI_PRINT(("Executor PP: Job %d Timeout on %s\n",
679 mali_pp_job_get_id(group->pp_running_job),
680 mali_group_core_description(group)));
682 int_result = mali_group_get_interrupt_result_pp(group);
683 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
684 mali_executor_unlock();
685 return _MALI_OSK_ERR_FAULT;
689 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
690 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
691 /* No interrupts signalled, so nothing to do */
692 mali_executor_unlock();
693 return _MALI_OSK_ERR_FAULT;
694 } else if (MALI_INTERRUPT_RESULT_SUCCESS == int_result) {
695 if (mali_group_is_virtual(group) && mali_group_pp_is_active(group)) {
696 /* Some child groups are still working, so nothing to do right now */
697 mali_executor_unlock();
698 return _MALI_OSK_ERR_FAULT;
702 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_NONE != int_result);
703 if (!mali_group_has_timed_out(group)) {
704 MALI_DEBUG_ASSERT(!mali_group_pp_is_active(group));
708 /*Add voltage scan function*/
710 if (MALI_INTERRUPT_RESULT_ERROR == int_result)
713 /* We should now have a real interrupt to handle */
715 MALI_DEBUG_PRINT(4, ("Executor: Group %s completed with %s\n",
716 mali_group_core_description(group),
717 (MALI_INTERRUPT_RESULT_ERROR == int_result) ?
718 "ERROR" : "success"));
720 if (in_upper_half && MALI_INTERRUPT_RESULT_ERROR == int_result) {
721 /* Don't bother to do processing of errors in upper half */
722 mali_group_mask_all_interrupts_pp(group);
723 mali_executor_unlock();
725 if (MALI_FALSE == time_out) {
726 mali_group_schedule_bottom_half_pp(group);
729 struct mali_pp_job *job = NULL;
732 success = (int_result == MALI_INTERRUPT_RESULT_SUCCESS) ?
733 MALI_TRUE : MALI_FALSE;
735 mali_executor_complete_group(group, success,
736 MALI_TRUE, NULL, &job);
738 mali_executor_unlock();
741 /* Notify user space and close the job object */
742 mali_scheduler_complete_pp_job(job,
743 num_physical_pp_cores_total,
744 MALI_TRUE, MALI_TRUE);
748 return _MALI_OSK_ERR_OK;
751 _mali_osk_errcode_t mali_executor_interrupt_mmu(struct mali_group *group,
752 mali_bool in_upper_half)
754 enum mali_interrupt_result int_result;
756 MALI_DEBUG_PRINT(4, ("Executor: MMU interrupt from %s in %s half\n",
757 mali_group_core_description(group),
758 in_upper_half ? "upper" : "bottom"));
760 mali_executor_lock();
761 if (!mali_group_is_working(group)) {
762 /* Not working, so nothing to do */
763 mali_executor_unlock();
764 return _MALI_OSK_ERR_FAULT;
767 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
768 MALI_DEBUG_ASSERT(mali_group_is_working(group));
770 int_result = mali_group_get_interrupt_result_mmu(group);
771 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
772 mali_executor_unlock();
773 return _MALI_OSK_ERR_FAULT;
776 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
777 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
778 /* No interrupts signalled, so nothing to do */
779 mali_executor_unlock();
780 return _MALI_OSK_ERR_FAULT;
783 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_ERROR == int_result);
786 /* We should now have a real interrupt to handle */
789 /* Don't bother to do processing of errors in upper half */
791 struct mali_group *parent = group->parent_group;
793 mali_mmu_mask_all_interrupts(group->mmu);
795 mali_executor_unlock();
797 if (NULL == parent) {
798 mali_group_schedule_bottom_half_mmu(group);
800 mali_group_schedule_bottom_half_mmu(parent);
804 struct mali_gp_job *gp_job = NULL;
805 struct mali_pp_job *pp_job = NULL;
809 u32 fault_address = mali_mmu_get_page_fault_addr(group->mmu);
810 u32 status = mali_mmu_get_status(group->mmu);
811 MALI_DEBUG_PRINT(2, ("Executor: Mali page fault detected at 0x%x from bus id %d of type %s on %s\n",
812 (void *)(uintptr_t)fault_address,
813 (status >> 6) & 0x1F,
814 (status & 32) ? "write" : "read",
815 group->mmu->hw_core.description));
816 MALI_DEBUG_PRINT(3, ("Executor: MMU rawstat = 0x%08X, MMU status = 0x%08X\n",
817 mali_mmu_get_rawstat(group->mmu), status));
820 mali_executor_complete_group(group, MALI_FALSE,
821 MALI_TRUE, &gp_job, &pp_job);
823 mali_executor_unlock();
825 if (NULL != gp_job) {
826 MALI_DEBUG_ASSERT(NULL == pp_job);
828 /* Notify user space and close the job object */
829 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
830 MALI_TRUE, MALI_TRUE);
831 } else if (NULL != pp_job) {
832 MALI_DEBUG_ASSERT(NULL == gp_job);
834 /* Notify user space and close the job object */
835 mali_scheduler_complete_pp_job(pp_job,
836 num_physical_pp_cores_total,
837 MALI_TRUE, MALI_TRUE);
841 return _MALI_OSK_ERR_OK;
844 void mali_executor_group_power_up(struct mali_group *groups[], u32 num_groups)
847 mali_bool child_groups_activated = MALI_FALSE;
848 mali_bool do_schedule = MALI_FALSE;
850 u32 num_activated = 0;
853 MALI_DEBUG_ASSERT_POINTER(groups);
854 MALI_DEBUG_ASSERT(0 < num_groups);
856 mali_executor_lock();
858 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups\n", num_groups));
860 for (i = 0; i < num_groups; i++) {
861 MALI_DEBUG_PRINT(3, ("Executor: powering up group %s\n",
862 mali_group_core_description(groups[i])));
864 mali_group_power_up(groups[i]);
866 if ((MALI_GROUP_STATE_ACTIVATION_PENDING != mali_group_get_state(groups[i]) ||
867 (MALI_TRUE != mali_executor_group_is_in_state(groups[i], EXEC_STATE_INACTIVE)))) {
868 /* nothing more to do for this group */
872 MALI_DEBUG_PRINT(3, ("Executor: activating group %s\n",
873 mali_group_core_description(groups[i])));
879 if (mali_group_is_in_virtual(groups[i])) {
881 * At least one child group of virtual group is powered on.
883 child_groups_activated = MALI_TRUE;
884 } else if (MALI_FALSE == mali_group_is_virtual(groups[i])) {
885 /* Set gp and pp not in virtual to active. */
886 mali_group_set_active(groups[i]);
889 /* Move group from inactive to idle list */
890 if (groups[i] == gp_group) {
891 MALI_DEBUG_ASSERT(EXEC_STATE_INACTIVE ==
893 gp_group_state = EXEC_STATE_IDLE;
894 } else if (MALI_FALSE == mali_group_is_in_virtual(groups[i])
895 && MALI_FALSE == mali_group_is_virtual(groups[i])) {
896 MALI_DEBUG_ASSERT(MALI_TRUE == mali_executor_group_is_in_state(groups[i],
897 EXEC_STATE_INACTIVE));
899 mali_executor_change_state_pp_physical(groups[i],
900 &group_list_inactive,
901 &group_list_inactive_count,
903 &group_list_idle_count);
906 do_schedule = MALI_TRUE;
909 if (mali_executor_has_virtual_group() &&
910 MALI_TRUE == child_groups_activated &&
911 MALI_GROUP_STATE_ACTIVATION_PENDING ==
912 mali_group_get_state(virtual_group)) {
914 * Try to active virtual group while it may be not sucessful every time,
915 * because there is one situation that not all of child groups are powered on
916 * in one time and virtual group is in activation pending state.
918 if (mali_group_set_active(virtual_group)) {
919 /* Move group from inactive to idle */
920 MALI_DEBUG_ASSERT(EXEC_STATE_INACTIVE ==
921 virtual_group_state);
922 virtual_group_state = EXEC_STATE_IDLE;
924 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated, 1 virtual activated.\n", num_groups, num_activated));
926 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated\n", num_groups, num_activated));
929 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated\n", num_groups, num_activated));
932 if (MALI_TRUE == do_schedule) {
933 /* Trigger a schedule */
934 mali_executor_schedule();
937 mali_executor_unlock();
940 void mali_executor_group_power_down(struct mali_group *groups[],
945 MALI_DEBUG_ASSERT_POINTER(groups);
946 MALI_DEBUG_ASSERT(0 < num_groups);
948 mali_executor_lock();
950 MALI_DEBUG_PRINT(3, ("Executor: powering down %u groups\n", num_groups));
952 for (i = 0; i < num_groups; i++) {
953 /* Groups must be either disabled or inactive */
954 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(groups[i],
955 EXEC_STATE_DISABLED) ||
956 mali_executor_group_is_in_state(groups[i],
957 EXEC_STATE_INACTIVE));
959 MALI_DEBUG_PRINT(3, ("Executor: powering down group %s\n",
960 mali_group_core_description(groups[i])));
962 mali_group_power_down(groups[i]);
965 MALI_DEBUG_PRINT(3, ("Executor: powering down %u groups completed\n", num_groups));
967 mali_executor_unlock();
970 void mali_executor_abort_session(struct mali_session_data *session)
972 struct mali_group *group;
973 struct mali_group *tmp_group;
975 MALI_DEBUG_ASSERT_POINTER(session);
976 MALI_DEBUG_ASSERT(session->is_aborting);
979 ("Executor: Aborting all jobs from session 0x%08X.\n",
982 mali_executor_lock();
984 if (mali_group_get_session(gp_group) == session) {
985 if (EXEC_STATE_WORKING == gp_group_state) {
986 struct mali_gp_job *gp_job = NULL;
988 mali_executor_complete_group(gp_group, MALI_FALSE,
989 MALI_TRUE, &gp_job, NULL);
991 MALI_DEBUG_ASSERT_POINTER(gp_job);
993 /* GP job completed, make sure it is freed */
994 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
995 MALI_FALSE, MALI_TRUE);
997 /* Same session, but not working, so just clear it */
998 mali_group_clear_session(gp_group);
1002 if (mali_executor_has_virtual_group()) {
1003 if (EXEC_STATE_WORKING == virtual_group_state
1004 && mali_group_get_session(virtual_group) == session) {
1005 struct mali_pp_job *pp_job = NULL;
1007 mali_executor_complete_group(virtual_group, MALI_FALSE,
1008 MALI_FALSE, NULL, &pp_job);
1010 if (NULL != pp_job) {
1011 /* PP job completed, make sure it is freed */
1012 mali_scheduler_complete_pp_job(pp_job, 0,
1013 MALI_FALSE, MALI_TRUE);
1018 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_working,
1019 struct mali_group, executor_list) {
1020 if (mali_group_get_session(group) == session) {
1021 struct mali_pp_job *pp_job = NULL;
1023 mali_executor_complete_group(group, MALI_FALSE,
1024 MALI_FALSE, NULL, &pp_job);
1026 if (NULL != pp_job) {
1027 /* PP job completed, make sure it is freed */
1028 mali_scheduler_complete_pp_job(pp_job, 0,
1029 MALI_FALSE, MALI_TRUE);
1034 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_idle, struct mali_group, executor_list) {
1035 mali_group_clear_session(group);
1038 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_inactive, struct mali_group, executor_list) {
1039 mali_group_clear_session(group);
1042 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_disabled, struct mali_group, executor_list) {
1043 mali_group_clear_session(group);
1046 mali_executor_unlock();
1050 void mali_executor_core_scaling_enable(void)
1052 /* PS: Core scaling is by default enabled */
1053 core_scaling_enabled = MALI_TRUE;
1056 void mali_executor_core_scaling_disable(void)
1058 core_scaling_enabled = MALI_FALSE;
1061 mali_bool mali_executor_core_scaling_is_enabled(void)
1063 return core_scaling_enabled;
1066 void mali_executor_group_enable(struct mali_group *group)
1068 MALI_DEBUG_ASSERT_POINTER(group);
1070 mali_executor_lock();
1072 if ((NULL != mali_group_get_gp_core(group) || NULL != mali_group_get_pp_core(group))
1073 && (mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))) {
1074 mali_executor_group_enable_internal(group);
1077 mali_executor_schedule();
1078 mali_executor_unlock();
1080 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1084 * If a physical group is inactive or idle, we should disable it immediately,
1085 * if group is in virtual, and virtual group is idle, disable given physical group in it.
1087 void mali_executor_group_disable(struct mali_group *group)
1089 MALI_DEBUG_ASSERT_POINTER(group);
1091 mali_executor_lock();
1093 if ((NULL != mali_group_get_gp_core(group) || NULL != mali_group_get_pp_core(group))
1094 && (!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))) {
1095 mali_executor_group_disable_internal(group);
1098 mali_executor_schedule();
1099 mali_executor_unlock();
1101 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1104 mali_bool mali_executor_group_is_disabled(struct mali_group *group)
1106 /* NB: This function is not optimized for time critical usage */
1110 MALI_DEBUG_ASSERT_POINTER(group);
1112 mali_executor_lock();
1113 ret = mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED);
1114 mali_executor_unlock();
1119 int mali_executor_set_perf_level(unsigned int target_core_nr, mali_bool override)
1121 if (target_core_nr == num_physical_pp_cores_enabled) return 0;
1122 if (MALI_FALSE == core_scaling_enabled && MALI_FALSE == override) return -EPERM;
1123 if (target_core_nr > num_physical_pp_cores_total) return -EINVAL;
1124 if (0 == target_core_nr) return -EINVAL;
1126 mali_executor_core_scale(target_core_nr);
1128 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1133 #if MALI_STATE_TRACKING
1134 u32 mali_executor_dump_state(char *buf, u32 size)
1137 struct mali_group *group;
1138 struct mali_group *temp;
1140 mali_executor_lock();
1142 switch (gp_group_state) {
1143 case EXEC_STATE_INACTIVE:
1144 n += _mali_osk_snprintf(buf + n, size - n,
1145 "GP group is in state INACTIVE\n");
1147 case EXEC_STATE_IDLE:
1148 n += _mali_osk_snprintf(buf + n, size - n,
1149 "GP group is in state IDLE\n");
1151 case EXEC_STATE_WORKING:
1152 n += _mali_osk_snprintf(buf + n, size - n,
1153 "GP group is in state WORKING\n");
1156 n += _mali_osk_snprintf(buf + n, size - n,
1157 "GP group is in unknown/illegal state %u\n",
1162 n += mali_group_dump_state(gp_group, buf + n, size - n);
1164 n += _mali_osk_snprintf(buf + n, size - n,
1165 "Physical PP groups in WORKING state (count = %u):\n",
1166 group_list_working_count);
1168 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, executor_list) {
1169 n += mali_group_dump_state(group, buf + n, size - n);
1172 n += _mali_osk_snprintf(buf + n, size - n,
1173 "Physical PP groups in IDLE state (count = %u):\n",
1174 group_list_idle_count);
1176 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, executor_list) {
1177 n += mali_group_dump_state(group, buf + n, size - n);
1180 n += _mali_osk_snprintf(buf + n, size - n,
1181 "Physical PP groups in INACTIVE state (count = %u):\n",
1182 group_list_inactive_count);
1184 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive, struct mali_group, executor_list) {
1185 n += mali_group_dump_state(group, buf + n, size - n);
1188 n += _mali_osk_snprintf(buf + n, size - n,
1189 "Physical PP groups in DISABLED state (count = %u):\n",
1190 group_list_disabled_count);
1192 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, executor_list) {
1193 n += mali_group_dump_state(group, buf + n, size - n);
1196 if (mali_executor_has_virtual_group()) {
1197 switch (virtual_group_state) {
1198 case EXEC_STATE_EMPTY:
1199 n += _mali_osk_snprintf(buf + n, size - n,
1200 "Virtual PP group is in state EMPTY\n");
1202 case EXEC_STATE_INACTIVE:
1203 n += _mali_osk_snprintf(buf + n, size - n,
1204 "Virtual PP group is in state INACTIVE\n");
1206 case EXEC_STATE_IDLE:
1207 n += _mali_osk_snprintf(buf + n, size - n,
1208 "Virtual PP group is in state IDLE\n");
1210 case EXEC_STATE_WORKING:
1211 n += _mali_osk_snprintf(buf + n, size - n,
1212 "Virtual PP group is in state WORKING\n");
1215 n += _mali_osk_snprintf(buf + n, size - n,
1216 "Virtual PP group is in unknown/illegal state %u\n",
1217 virtual_group_state);
1221 n += mali_group_dump_state(virtual_group, buf + n, size - n);
1224 mali_executor_unlock();
1226 n += _mali_osk_snprintf(buf + n, size - n, "\n");
1232 _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args)
1234 MALI_DEBUG_ASSERT_POINTER(args);
1235 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1236 args->number_of_total_cores = num_physical_pp_cores_total;
1237 args->number_of_enabled_cores = num_physical_pp_cores_enabled;
1238 return _MALI_OSK_ERR_OK;
1241 _mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args)
1243 MALI_DEBUG_ASSERT_POINTER(args);
1244 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1245 args->version = pp_version;
1246 return _MALI_OSK_ERR_OK;
1249 _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args)
1251 MALI_DEBUG_ASSERT_POINTER(args);
1252 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1253 args->number_of_cores = 1;
1254 return _MALI_OSK_ERR_OK;
1257 _mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args)
1259 MALI_DEBUG_ASSERT_POINTER(args);
1260 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1261 args->version = gp_version;
1262 return _MALI_OSK_ERR_OK;
1265 _mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args)
1267 struct mali_session_data *session;
1268 struct mali_gp_job *job;
1270 MALI_DEBUG_ASSERT_POINTER(args);
1271 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1273 session = (struct mali_session_data *)(uintptr_t)args->ctx;
1275 if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) {
1276 _mali_osk_notification_t *new_notification = NULL;
1278 new_notification = _mali_osk_notification_create(
1279 _MALI_NOTIFICATION_GP_STALLED,
1280 sizeof(_mali_uk_gp_job_suspended_s));
1282 if (NULL != new_notification) {
1283 MALI_DEBUG_PRINT(3, ("Executor: Resuming job %u with new heap; 0x%08X - 0x%08X\n",
1284 args->cookie, args->arguments[0], args->arguments[1]));
1286 mali_executor_lock();
1288 /* Resume the job in question if it is still running */
1289 job = mali_group_get_running_gp_job(gp_group);
1291 args->cookie == mali_gp_job_get_id(job) &&
1292 session == mali_gp_job_get_session(job)) {
1294 * Correct job is running, resume with new heap
1297 mali_gp_job_set_oom_notification(job,
1300 /* This will also re-enable interrupts */
1301 mali_group_resume_gp_with_new_heap(gp_group,
1304 args->arguments[1]);
1306 mali_executor_unlock();
1307 return _MALI_OSK_ERR_OK;
1309 MALI_PRINT_ERROR(("Executor: Unable to resume, GP job no longer running.\n"));
1311 _mali_osk_notification_delete(new_notification);
1313 mali_executor_unlock();
1314 return _MALI_OSK_ERR_FAULT;
1317 MALI_PRINT_ERROR(("Executor: Failed to allocate notification object. Will abort GP job.\n"));
1320 MALI_DEBUG_PRINT(2, ("Executor: Aborting job %u, no new heap provided\n", args->cookie));
1323 mali_executor_lock();
1325 /* Abort the job in question if it is still running */
1326 job = mali_group_get_running_gp_job(gp_group);
1328 args->cookie == mali_gp_job_get_id(job) &&
1329 session == mali_gp_job_get_session(job)) {
1330 /* Correct job is still running */
1331 struct mali_gp_job *job_done = NULL;
1333 mali_executor_complete_group(gp_group, MALI_FALSE,
1334 MALI_TRUE, &job_done, NULL);
1336 /* The same job should have completed */
1337 MALI_DEBUG_ASSERT(job_done == job);
1339 /* GP job completed, make sure it is freed */
1340 mali_scheduler_complete_gp_job(job_done, MALI_FALSE,
1341 MALI_TRUE, MALI_TRUE);
1344 mali_executor_unlock();
1345 return _MALI_OSK_ERR_FAULT;
1350 * ---------- Implementation of static functions ----------
1353 static void mali_executor_lock(void)
1355 _mali_osk_spinlock_irq_lock(mali_executor_lock_obj);
1356 MALI_DEBUG_PRINT(5, ("Executor: lock taken\n"));
1359 static void mali_executor_unlock(void)
1361 MALI_DEBUG_PRINT(5, ("Executor: Releasing lock\n"));
1362 _mali_osk_spinlock_irq_unlock(mali_executor_lock_obj);
1365 static mali_bool mali_executor_is_suspended(void *data)
1369 /* This callback does not use the data pointer. */
1372 mali_executor_lock();
1374 ret = pause_count > 0 && !mali_executor_is_working();
1376 mali_executor_unlock();
1381 static mali_bool mali_executor_is_working()
1383 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1385 return (0 != group_list_working_count ||
1386 EXEC_STATE_WORKING == gp_group_state ||
1387 EXEC_STATE_WORKING == virtual_group_state);
1390 static void mali_executor_disable_empty_virtual(void)
1392 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1393 MALI_DEBUG_ASSERT(virtual_group_state != EXEC_STATE_EMPTY);
1394 MALI_DEBUG_ASSERT(virtual_group_state != EXEC_STATE_WORKING);
1396 if (mali_group_is_empty(virtual_group)) {
1397 virtual_group_state = EXEC_STATE_EMPTY;
1401 static mali_bool mali_executor_physical_rejoin_virtual(struct mali_group *group)
1403 mali_bool trigger_pm_update = MALI_FALSE;
1405 MALI_DEBUG_ASSERT_POINTER(group);
1406 /* Only rejoining after job has completed (still active) */
1407 MALI_DEBUG_ASSERT(MALI_GROUP_STATE_ACTIVE ==
1408 mali_group_get_state(group));
1409 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1410 MALI_DEBUG_ASSERT(MALI_TRUE == mali_executor_has_virtual_group());
1411 MALI_DEBUG_ASSERT(MALI_FALSE == mali_group_is_virtual(group));
1413 /* Make sure group and virtual group have same status */
1415 if (MALI_GROUP_STATE_INACTIVE == mali_group_get_state(virtual_group)) {
1416 if (mali_group_deactivate(group)) {
1417 trigger_pm_update = MALI_TRUE;
1420 if (virtual_group_state == EXEC_STATE_EMPTY) {
1421 virtual_group_state = EXEC_STATE_INACTIVE;
1423 } else if (MALI_GROUP_STATE_ACTIVATION_PENDING ==
1424 mali_group_get_state(virtual_group)) {
1426 * Activation is pending for virtual group, leave
1427 * this child group as active.
1429 if (virtual_group_state == EXEC_STATE_EMPTY) {
1430 virtual_group_state = EXEC_STATE_INACTIVE;
1433 MALI_DEBUG_ASSERT(MALI_GROUP_STATE_ACTIVE ==
1434 mali_group_get_state(virtual_group));
1436 if (virtual_group_state == EXEC_STATE_EMPTY) {
1437 virtual_group_state = EXEC_STATE_IDLE;
1441 /* Remove group from idle list */
1442 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(group,
1444 _mali_osk_list_delinit(&group->executor_list);
1445 group_list_idle_count--;
1448 * And finally rejoin the virtual group
1449 * group will start working on same job as virtual_group,
1450 * if virtual_group is working on a job
1452 mali_group_add_group(virtual_group, group);
1454 return trigger_pm_update;
1457 static mali_bool mali_executor_has_virtual_group(void)
1459 #if defined(CONFIG_MALI450)
1460 return (NULL != virtual_group) ? MALI_TRUE : MALI_FALSE;
1463 #endif /* defined(CONFIG_MALI450) */
1466 static mali_bool mali_executor_virtual_group_is_usable(void)
1468 #if defined(CONFIG_MALI450)
1469 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1470 return (EXEC_STATE_INACTIVE == virtual_group_state ||
1471 EXEC_STATE_IDLE == virtual_group_state) ?
1472 MALI_TRUE : MALI_FALSE;
1475 #endif /* defined(CONFIG_MALI450) */
1478 static mali_bool mali_executor_tackle_gp_bound(void)
1480 struct mali_pp_job *job;
1482 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1484 job = mali_scheduler_job_pp_physical_peek();
1486 if (NULL != job && MALI_TRUE == mali_is_mali400()) {
1487 if (0 < group_list_working_count &&
1488 mali_pp_job_is_large_and_unstarted(job)) {
1497 * This is where jobs are actually started.
1499 static void mali_executor_schedule(void)
1502 u32 num_physical_needed = 0;
1503 u32 num_physical_to_process = 0;
1504 mali_bool trigger_pm_update = MALI_FALSE;
1505 mali_bool deactivate_idle_group = MALI_TRUE;
1507 /* Physical groups + jobs to start in this function */
1508 struct mali_group *groups_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1509 struct mali_pp_job *jobs_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1510 u32 sub_jobs_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1511 int num_jobs_to_start = 0;
1513 /* Virtual job to start in this function */
1514 struct mali_pp_job *virtual_job_to_start = NULL;
1516 /* GP job to start in this function */
1517 struct mali_gp_job *gp_job_to_start = NULL;
1519 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1521 if (pause_count > 0) {
1522 /* Execution is suspended, don't schedule any jobs. */
1526 /* Lock needed in order to safely handle the job queues */
1527 mali_scheduler_lock();
1529 /* 1. Activate gp firstly if have gp job queued. */
1530 if (EXEC_STATE_INACTIVE == gp_group_state &&
1531 0 < mali_scheduler_job_gp_count()) {
1533 enum mali_group_state state =
1534 mali_group_activate(gp_group);
1535 if (MALI_GROUP_STATE_ACTIVE == state) {
1536 /* Set GP group state to idle */
1537 gp_group_state = EXEC_STATE_IDLE;
1539 trigger_pm_update = MALI_TRUE;
1543 /* 2. Prepare as many physical groups as needed/possible */
1545 num_physical_needed = mali_scheduler_job_physical_head_count();
1547 /* On mali-450 platform, we don't need to enter in this block frequently. */
1548 if (0 < num_physical_needed) {
1550 if (num_physical_needed <= group_list_idle_count) {
1551 /* We have enough groups on idle list already */
1552 num_physical_to_process = num_physical_needed;
1553 num_physical_needed = 0;
1555 /* We need to get a hold of some more groups */
1556 num_physical_to_process = group_list_idle_count;
1557 num_physical_needed -= group_list_idle_count;
1560 if (0 < num_physical_needed) {
1562 /* 2.1. Activate groups which are inactive */
1564 struct mali_group *group;
1565 struct mali_group *temp;
1567 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive,
1568 struct mali_group, executor_list) {
1569 enum mali_group_state state =
1570 mali_group_activate(group);
1571 if (MALI_GROUP_STATE_ACTIVE == state) {
1572 /* Move from inactive to idle */
1573 mali_executor_change_state_pp_physical(group,
1574 &group_list_inactive,
1575 &group_list_inactive_count,
1577 &group_list_idle_count);
1578 num_physical_to_process++;
1580 trigger_pm_update = MALI_TRUE;
1583 num_physical_needed--;
1584 if (0 == num_physical_needed) {
1585 /* We have activated all the groups we need */
1591 if (mali_executor_virtual_group_is_usable()) {
1594 * 2.2. And finally, steal and activate groups
1595 * from virtual group if we need even more
1597 while (0 < num_physical_needed) {
1598 struct mali_group *group;
1600 group = mali_group_acquire_group(virtual_group);
1601 if (NULL != group) {
1602 enum mali_group_state state;
1604 mali_executor_disable_empty_virtual();
1606 state = mali_group_activate(group);
1607 if (MALI_GROUP_STATE_ACTIVE == state) {
1608 /* Group is ready, add to idle list */
1610 &group->executor_list,
1612 group_list_idle_count++;
1613 num_physical_to_process++;
1616 * Group is not ready yet,
1617 * add to inactive list
1620 &group->executor_list,
1621 &group_list_inactive);
1622 group_list_inactive_count++;
1624 trigger_pm_update = MALI_TRUE;
1626 num_physical_needed--;
1629 * We could not get enough groups
1630 * from the virtual group.
1637 /* 2.3. Assign physical jobs to groups */
1639 if (0 < num_physical_to_process) {
1640 struct mali_group *group;
1641 struct mali_group *temp;
1643 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle,
1644 struct mali_group, executor_list) {
1645 struct mali_pp_job *job = NULL;
1646 u32 sub_job = MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS;
1648 MALI_DEBUG_ASSERT(num_jobs_to_start <
1649 MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS);
1651 MALI_DEBUG_ASSERT(0 <
1652 mali_scheduler_job_physical_head_count());
1654 if (mali_executor_hint_is_enabled(
1655 MALI_EXECUTOR_HINT_GP_BOUND)) {
1656 if (MALI_TRUE == mali_executor_tackle_gp_bound()) {
1659 * don't start this right now.
1661 deactivate_idle_group = MALI_FALSE;
1662 num_physical_to_process = 0;
1667 job = mali_scheduler_job_pp_physical_get(
1670 MALI_DEBUG_ASSERT_POINTER(job);
1671 MALI_DEBUG_ASSERT(sub_job <= MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS);
1673 /* Put job + group on list of jobs to start later on */
1675 groups_to_start[num_jobs_to_start] = group;
1676 jobs_to_start[num_jobs_to_start] = job;
1677 sub_jobs_to_start[num_jobs_to_start] = sub_job;
1678 num_jobs_to_start++;
1680 /* Move group from idle to working */
1681 mali_executor_change_state_pp_physical(group,
1683 &group_list_idle_count,
1684 &group_list_working,
1685 &group_list_working_count);
1687 num_physical_to_process--;
1688 if (0 == num_physical_to_process) {
1689 /* Got all we needed */
1696 /* 3. Activate virtual group, if needed */
1698 if (EXEC_STATE_INACTIVE == virtual_group_state &&
1699 0 < mali_scheduler_job_next_is_virtual()) {
1700 enum mali_group_state state =
1701 mali_group_activate(virtual_group);
1702 if (MALI_GROUP_STATE_ACTIVE == state) {
1703 /* Set virtual group state to idle */
1704 virtual_group_state = EXEC_STATE_IDLE;
1706 trigger_pm_update = MALI_TRUE;
1710 /* 4. To power up group asap, we trigger pm update here. */
1712 if (MALI_TRUE == trigger_pm_update) {
1713 trigger_pm_update = MALI_FALSE;
1714 mali_pm_update_async();
1717 /* 5. Deactivate idle pp group */
1719 if (MALI_TRUE == mali_executor_deactivate_list_idle(deactivate_idle_group
1720 && (!mali_timeline_has_physical_pp_job()))) {
1721 trigger_pm_update = MALI_TRUE;
1724 /* 6. Assign jobs to idle virtual group (or deactivate if no job) */
1726 if (EXEC_STATE_IDLE == virtual_group_state) {
1727 if (0 < mali_scheduler_job_next_is_virtual()) {
1728 virtual_job_to_start =
1729 mali_scheduler_job_pp_virtual_get();
1730 virtual_group_state = EXEC_STATE_WORKING;
1731 } else if (!mali_timeline_has_virtual_pp_job()) {
1732 virtual_group_state = EXEC_STATE_INACTIVE;
1734 if (mali_group_deactivate(virtual_group)) {
1735 trigger_pm_update = MALI_TRUE;
1740 /* 7. Assign job to idle GP group (or deactivate if no job) */
1742 if (EXEC_STATE_IDLE == gp_group_state) {
1743 if (0 < mali_scheduler_job_gp_count()) {
1744 gp_job_to_start = mali_scheduler_job_gp_get();
1745 gp_group_state = EXEC_STATE_WORKING;
1746 } else if (!mali_timeline_has_gp_job()) {
1747 gp_group_state = EXEC_STATE_INACTIVE;
1748 if (mali_group_deactivate(gp_group)) {
1749 trigger_pm_update = MALI_TRUE;
1754 /* 8. We no longer need the schedule/queue lock */
1756 mali_scheduler_unlock();
1760 if (NULL != virtual_job_to_start) {
1761 MALI_DEBUG_ASSERT(!mali_group_pp_is_active(virtual_group));
1762 mali_group_start_pp_job(virtual_group,
1763 virtual_job_to_start, 0);
1766 for (i = 0; i < num_jobs_to_start; i++) {
1767 MALI_DEBUG_ASSERT(!mali_group_pp_is_active(
1768 groups_to_start[i]));
1769 mali_group_start_pp_job(groups_to_start[i],
1771 sub_jobs_to_start[i]);
1774 MALI_DEBUG_ASSERT_POINTER(gp_group);
1776 if (NULL != gp_job_to_start) {
1777 MALI_DEBUG_ASSERT(!mali_group_gp_is_active(gp_group));
1778 mali_group_start_gp_job(gp_group, gp_job_to_start);
1781 /* 10. Trigger any pending PM updates */
1782 if (MALI_TRUE == trigger_pm_update) {
1783 mali_pm_update_async();
1787 /* Handler for deferred schedule requests */
1788 static void mali_executor_wq_schedule(void *arg)
1791 mali_executor_lock();
1792 mali_executor_schedule();
1793 mali_executor_unlock();
1796 static void mali_executor_send_gp_oom_to_user(struct mali_gp_job *job)
1798 _mali_uk_gp_job_suspended_s *jobres;
1799 _mali_osk_notification_t *notification;
1801 notification = mali_gp_job_get_oom_notification(job);
1804 * Remember the id we send to user space, so we have something to
1805 * verify when we get a response
1807 gp_returned_cookie = mali_gp_job_get_id(job);
1809 jobres = (_mali_uk_gp_job_suspended_s *)notification->result_buffer;
1810 jobres->user_job_ptr = mali_gp_job_get_user_id(job);
1811 jobres->cookie = gp_returned_cookie;
1813 mali_session_send_notification(mali_gp_job_get_session(job),
1816 static struct mali_gp_job *mali_executor_complete_gp(struct mali_group *group,
1818 mali_bool release_jobs)
1820 struct mali_gp_job *job;
1822 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1824 /* Extracts the needed HW status from core and reset */
1825 job = mali_group_complete_gp(group, success);
1827 MALI_DEBUG_ASSERT_POINTER(job);
1829 /* Core is now ready to go into idle list */
1830 gp_group_state = EXEC_STATE_IDLE;
1833 /* This will potentially queue more GP and PP jobs */
1834 mali_timeline_tracker_release(&job->tracker);
1837 mali_gp_job_signal_pp_tracker(job, success);
1843 static struct mali_pp_job *mali_executor_complete_pp(struct mali_group *group,
1845 mali_bool release_jobs)
1847 struct mali_pp_job *job;
1849 mali_bool job_is_done;
1851 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1853 /* Extracts the needed HW status from core and reset */
1854 job = mali_group_complete_pp(group, success, &sub_job);
1856 MALI_DEBUG_ASSERT_POINTER(job);
1858 /* Core is now ready to go into idle list */
1859 if (mali_group_is_virtual(group)) {
1860 virtual_group_state = EXEC_STATE_IDLE;
1862 /* Move from working to idle state */
1863 mali_executor_change_state_pp_physical(group,
1864 &group_list_working,
1865 &group_list_working_count,
1867 &group_list_idle_count);
1870 /* It is the executor module which owns the jobs themselves by now */
1871 mali_pp_job_mark_sub_job_completed(job, success);
1872 job_is_done = mali_pp_job_is_complete(job);
1874 if (job_is_done && release_jobs) {
1875 /* This will potentially queue more GP and PP jobs */
1876 mali_timeline_tracker_release(&job->tracker);
1882 static void mali_executor_complete_group(struct mali_group *group,
1884 mali_bool release_jobs,
1885 struct mali_gp_job **gp_job_done,
1886 struct mali_pp_job **pp_job_done)
1888 struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
1889 struct mali_pp_core *pp_core = mali_group_get_pp_core(group);
1890 struct mali_gp_job *gp_job = NULL;
1891 struct mali_pp_job *pp_job = NULL;
1892 mali_bool pp_job_is_done = MALI_TRUE;
1894 if (NULL != gp_core) {
1895 gp_job = mali_executor_complete_gp(group,
1896 success, release_jobs);
1898 MALI_DEBUG_ASSERT_POINTER(pp_core);
1899 MALI_IGNORE(pp_core);
1900 pp_job = mali_executor_complete_pp(group,
1901 success, release_jobs);
1903 pp_job_is_done = mali_pp_job_is_complete(pp_job);
1906 if (pause_count > 0) {
1907 /* Execution has been suspended */
1909 if (!mali_executor_is_working()) {
1910 /* Last job completed, wake up sleepers */
1911 _mali_osk_wait_queue_wake_up(
1912 executor_working_wait_queue);
1914 } else if (MALI_TRUE == mali_group_disable_requested(group)) {
1915 mali_executor_core_scale_in_group_complete(group);
1917 mali_executor_schedule();
1919 /* try to schedule new jobs */
1920 mali_executor_schedule();
1923 if (NULL != gp_job) {
1924 MALI_DEBUG_ASSERT_POINTER(gp_job_done);
1925 *gp_job_done = gp_job;
1926 } else if (pp_job_is_done) {
1927 MALI_DEBUG_ASSERT_POINTER(pp_job);
1928 MALI_DEBUG_ASSERT_POINTER(pp_job_done);
1929 *pp_job_done = pp_job;
1933 static void mali_executor_change_state_pp_physical(struct mali_group *group,
1934 _mali_osk_list_t *old_list,
1936 _mali_osk_list_t *new_list,
1940 * It's a bit more complicated to change the state for the physical PP
1941 * groups since their state is determined by the list they are on.
1944 mali_bool found = MALI_FALSE;
1945 struct mali_group *group_iter;
1946 struct mali_group *temp;
1947 u32 old_counted = 0;
1948 u32 new_counted = 0;
1950 MALI_DEBUG_ASSERT_POINTER(group);
1951 MALI_DEBUG_ASSERT_POINTER(old_list);
1952 MALI_DEBUG_ASSERT_POINTER(old_count);
1953 MALI_DEBUG_ASSERT_POINTER(new_list);
1954 MALI_DEBUG_ASSERT_POINTER(new_count);
1957 * Verify that group is present on old list,
1958 * and that the count is correct
1961 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, old_list,
1962 struct mali_group, executor_list) {
1964 if (group == group_iter) {
1969 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, new_list,
1970 struct mali_group, executor_list) {
1974 if (MALI_FALSE == found) {
1975 if (old_list == &group_list_idle) {
1976 MALI_DEBUG_PRINT(1, (" old Group list is idle,"));
1977 } else if (old_list == &group_list_inactive) {
1978 MALI_DEBUG_PRINT(1, (" old Group list is inactive,"));
1979 } else if (old_list == &group_list_working) {
1980 MALI_DEBUG_PRINT(1, (" old Group list is working,"));
1981 } else if (old_list == &group_list_disabled) {
1982 MALI_DEBUG_PRINT(1, (" old Group list is disable,"));
1985 if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_WORKING)) {
1986 MALI_DEBUG_PRINT(1, (" group in working \n"));
1987 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_INACTIVE)) {
1988 MALI_DEBUG_PRINT(1, (" group in inactive \n"));
1989 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_IDLE)) {
1990 MALI_DEBUG_PRINT(1, (" group in idle \n"));
1991 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED)) {
1992 MALI_DEBUG_PRINT(1, (" but group in disabled \n"));
1996 MALI_DEBUG_ASSERT(MALI_TRUE == found);
1997 MALI_DEBUG_ASSERT(0 < (*old_count));
1998 MALI_DEBUG_ASSERT((*old_count) == old_counted);
1999 MALI_DEBUG_ASSERT((*new_count) == new_counted);
2002 _mali_osk_list_move(&group->executor_list, new_list);
2007 static void mali_executor_set_state_pp_physical(struct mali_group *group,
2008 _mali_osk_list_t *new_list,
2011 _mali_osk_list_add(&group->executor_list, new_list);
2015 static mali_bool mali_executor_group_is_in_state(struct mali_group *group,
2016 enum mali_executor_state_t state)
2018 MALI_DEBUG_ASSERT_POINTER(group);
2019 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2021 if (gp_group == group) {
2022 if (gp_group_state == state) {
2025 } else if (virtual_group == group || mali_group_is_in_virtual(group)) {
2026 if (virtual_group_state == state) {
2030 /* Physical PP group */
2031 struct mali_group *group_iter;
2032 struct mali_group *temp;
2033 _mali_osk_list_t *list;
2035 if (EXEC_STATE_DISABLED == state) {
2036 list = &group_list_disabled;
2037 } else if (EXEC_STATE_INACTIVE == state) {
2038 list = &group_list_inactive;
2039 } else if (EXEC_STATE_IDLE == state) {
2040 list = &group_list_idle;
2042 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING == state);
2043 list = &group_list_working;
2046 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, list,
2047 struct mali_group, executor_list) {
2048 if (group_iter == group) {
2054 /* group not in correct state */
2058 static void mali_executor_group_enable_internal(struct mali_group *group)
2060 MALI_DEBUG_ASSERT(group);
2061 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2062 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED));
2064 /* Put into inactive state (== "lowest" enabled state) */
2065 if (group == gp_group) {
2066 MALI_DEBUG_ASSERT(EXEC_STATE_DISABLED == gp_group_state);
2067 gp_group_state = EXEC_STATE_INACTIVE;
2069 mali_executor_change_state_pp_physical(group,
2070 &group_list_disabled,
2071 &group_list_disabled_count,
2072 &group_list_inactive,
2073 &group_list_inactive_count);
2075 ++num_physical_pp_cores_enabled;
2076 MALI_DEBUG_PRINT(4, ("Enabling group id %d \n", group->pp_core->core_id));
2079 if (MALI_GROUP_STATE_ACTIVE == mali_group_activate(group)) {
2080 MALI_DEBUG_ASSERT(MALI_TRUE == mali_group_power_is_on(group));
2082 /* Move from inactive to idle */
2083 if (group == gp_group) {
2084 gp_group_state = EXEC_STATE_IDLE;
2086 mali_executor_change_state_pp_physical(group,
2087 &group_list_inactive,
2088 &group_list_inactive_count,
2090 &group_list_idle_count);
2092 if (mali_executor_has_virtual_group()) {
2093 if (mali_executor_physical_rejoin_virtual(group)) {
2094 mali_pm_update_async();
2099 mali_pm_update_async();
2103 static void mali_executor_group_disable_internal(struct mali_group *group)
2107 MALI_DEBUG_ASSERT_POINTER(group);
2108 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2109 MALI_DEBUG_ASSERT(!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED));
2111 working = mali_executor_group_is_in_state(group, EXEC_STATE_WORKING);
2112 if (MALI_TRUE == working) {
2113 /** Group to be disabled once it completes current work,
2114 * when virtual group completes, also check child groups for this flag */
2115 mali_group_set_disable_request(group, MALI_TRUE);
2119 /* Put into disabled state */
2120 if (group == gp_group) {
2122 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != gp_group_state);
2123 gp_group_state = EXEC_STATE_DISABLED;
2125 if (mali_group_is_in_virtual(group)) {
2126 /* A child group of virtual group. move the specific group from virtual group */
2127 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != virtual_group_state);
2129 mali_executor_set_state_pp_physical(group,
2130 &group_list_disabled,
2131 &group_list_disabled_count);
2133 mali_group_remove_group(virtual_group, group);
2134 mali_executor_disable_empty_virtual();
2136 mali_executor_change_group_status_disabled(group);
2139 --num_physical_pp_cores_enabled;
2140 MALI_DEBUG_PRINT(4, ("Disabling group id %d \n", group->pp_core->core_id));
2143 if (MALI_GROUP_STATE_INACTIVE != group->state) {
2144 if (MALI_TRUE == mali_group_deactivate(group)) {
2145 mali_pm_update_async();
2150 static void mali_executor_notify_core_change(u32 num_cores)
2152 mali_bool done = MALI_FALSE;
2154 if (mali_is_mali450()) {
2159 * This function gets a bit complicated because we can't hold the session lock while
2160 * allocating notification objects.
2164 u32 num_sessions_alloc;
2165 u32 num_sessions_with_lock;
2166 u32 used_notification_objects = 0;
2167 _mali_osk_notification_t **notobjs;
2169 /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */
2170 num_sessions_alloc = mali_session_get_count();
2171 if (0 == num_sessions_alloc) {
2172 /* No sessions to report to */
2176 notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc);
2177 if (NULL == notobjs) {
2178 MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n"));
2179 /* there is probably no point in trying again, system must be really low on memory and probably unusable now anyway */
2183 for (i = 0; i < num_sessions_alloc; i++) {
2184 notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_NUM_CORE_CHANGE, sizeof(_mali_uk_pp_num_cores_changed_s));
2185 if (NULL != notobjs[i]) {
2186 _mali_uk_pp_num_cores_changed_s *data = notobjs[i]->result_buffer;
2187 data->number_of_enabled_cores = num_cores;
2189 MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure %u)\n", i));
2193 mali_session_lock();
2195 /* number of sessions will not change while we hold the lock */
2196 num_sessions_with_lock = mali_session_get_count();
2198 if (num_sessions_alloc >= num_sessions_with_lock) {
2199 /* We have allocated enough notification objects for all the sessions atm */
2200 struct mali_session_data *session, *tmp;
2201 MALI_SESSION_FOREACH(session, tmp, link) {
2202 MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc);
2203 if (NULL != notobjs[used_notification_objects]) {
2204 mali_session_send_notification(session, notobjs[used_notification_objects]);
2205 notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */
2207 used_notification_objects++;
2212 mali_session_unlock();
2214 /* Delete any remaining/unused notification objects */
2215 for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) {
2216 if (NULL != notobjs[used_notification_objects]) {
2217 _mali_osk_notification_delete(notobjs[used_notification_objects]);
2221 _mali_osk_free(notobjs);
2225 static mali_bool mali_executor_core_scaling_is_done(void *data)
2229 mali_bool ret = MALI_TRUE;
2233 mali_executor_lock();
2235 num_groups = mali_group_get_glob_num_groups();
2237 for (i = 0; i < num_groups; i++) {
2238 struct mali_group *group = mali_group_get_glob_group(i);
2240 if (NULL != group) {
2241 if (MALI_TRUE == group->disable_requested && NULL != mali_group_get_pp_core(group)) {
2247 mali_executor_unlock();
2252 static void mali_executor_wq_notify_core_change(void *arg)
2256 if (mali_is_mali450()) {
2260 _mali_osk_wait_queue_wait_event(executor_notify_core_change_wait_queue,
2261 mali_executor_core_scaling_is_done, NULL);
2263 mali_executor_notify_core_change(num_physical_pp_cores_enabled);
2267 * Clear all disable request from the _last_ core scaling behavior.
2269 static void mali_executor_core_scaling_reset(void)
2274 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2276 num_groups = mali_group_get_glob_num_groups();
2278 for (i = 0; i < num_groups; i++) {
2279 struct mali_group *group = mali_group_get_glob_group(i);
2281 if (NULL != group) {
2282 group->disable_requested = MALI_FALSE;
2286 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2287 core_scaling_delay_up_mask[i] = 0;
2291 static void mali_executor_core_scale(unsigned int target_core_nr)
2293 int current_core_scaling_mask[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
2294 int target_core_scaling_mask[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
2295 mali_bool update_global_core_scaling_mask = MALI_FALSE;
2298 MALI_DEBUG_ASSERT(0 < target_core_nr);
2299 MALI_DEBUG_ASSERT(num_physical_pp_cores_total >= target_core_nr);
2301 mali_executor_lock();
2303 if (target_core_nr < num_physical_pp_cores_enabled) {
2304 MALI_DEBUG_PRINT(2, ("Requesting %d cores: disabling %d cores\n", target_core_nr, num_physical_pp_cores_enabled - target_core_nr));
2306 MALI_DEBUG_PRINT(2, ("Requesting %d cores: enabling %d cores\n", target_core_nr, target_core_nr - num_physical_pp_cores_enabled));
2309 /* When a new core scaling request is comming, we should remove the un-doing
2310 * part of the last core scaling request. It's safe because we have only one
2311 * lock(executor lock) protection. */
2312 mali_executor_core_scaling_reset();
2314 mali_pm_get_best_power_cost_mask(num_physical_pp_cores_enabled, current_core_scaling_mask);
2315 mali_pm_get_best_power_cost_mask(target_core_nr, target_core_scaling_mask);
2317 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2318 target_core_scaling_mask[i] = target_core_scaling_mask[i] - current_core_scaling_mask[i];
2319 MALI_DEBUG_PRINT(5, ("target_core_scaling_mask[%d] = %d\n", i, target_core_scaling_mask[i]));
2322 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2323 if (0 > target_core_scaling_mask[i]) {
2324 struct mali_pm_domain *domain;
2326 domain = mali_pm_domain_get_from_index(i);
2328 /* Domain is valid and has pp cores */
2329 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2330 struct mali_group *group;
2331 struct mali_group *temp;
2333 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2334 if (NULL != mali_group_get_pp_core(group) && (!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))
2335 && (!mali_group_is_virtual(group))) {
2336 mali_executor_group_disable_internal(group);
2337 target_core_scaling_mask[i]++;
2338 if ((0 == target_core_scaling_mask[i])) {
2348 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2350 * Target_core_scaling_mask[i] is bigger than 0,
2351 * means we need to enable some pp cores in
2352 * this domain whose domain index is i.
2354 if (0 < target_core_scaling_mask[i]) {
2355 struct mali_pm_domain *domain;
2357 if (num_physical_pp_cores_enabled >= target_core_nr) {
2358 update_global_core_scaling_mask = MALI_TRUE;
2362 domain = mali_pm_domain_get_from_index(i);
2364 /* Domain is valid and has pp cores */
2365 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2366 struct mali_group *group;
2367 struct mali_group *temp;
2369 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2370 if (NULL != mali_group_get_pp_core(group) && mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED)
2371 && (!mali_group_is_virtual(group))) {
2372 mali_executor_group_enable_internal(group);
2373 target_core_scaling_mask[i]--;
2375 if ((0 == target_core_scaling_mask[i]) || num_physical_pp_cores_enabled == target_core_nr) {
2385 * Here, we may still have some pp cores not been enabled because of some
2386 * pp cores need to be disabled are still in working state.
2388 if (update_global_core_scaling_mask) {
2389 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2390 if (0 < target_core_scaling_mask[i]) {
2391 core_scaling_delay_up_mask[i] = target_core_scaling_mask[i];
2396 mali_executor_schedule();
2397 mali_executor_unlock();
2400 static void mali_executor_core_scale_in_group_complete(struct mali_group *group)
2402 int num_pp_cores_disabled = 0;
2403 int num_pp_cores_to_enable = 0;
2406 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2407 MALI_DEBUG_ASSERT(MALI_TRUE == mali_group_disable_requested(group));
2409 /* Disable child group of virtual group */
2410 if (mali_group_is_virtual(group)) {
2411 struct mali_group *child;
2412 struct mali_group *temp;
2414 _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) {
2415 if (MALI_TRUE == mali_group_disable_requested(child)) {
2416 mali_group_set_disable_request(child, MALI_FALSE);
2417 mali_executor_group_disable_internal(child);
2418 num_pp_cores_disabled++;
2421 mali_group_set_disable_request(group, MALI_FALSE);
2423 mali_executor_group_disable_internal(group);
2424 mali_group_set_disable_request(group, MALI_FALSE);
2425 if (NULL != mali_group_get_pp_core(group)) {
2426 num_pp_cores_disabled++;
2430 num_pp_cores_to_enable = num_pp_cores_disabled;
2432 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2433 if (0 < core_scaling_delay_up_mask[i]) {
2434 struct mali_pm_domain *domain;
2436 if (0 == num_pp_cores_to_enable) {
2440 domain = mali_pm_domain_get_from_index(i);
2442 /* Domain is valid and has pp cores */
2443 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2444 struct mali_group *disabled_group;
2445 struct mali_group *temp;
2447 _MALI_OSK_LIST_FOREACHENTRY(disabled_group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2448 if (NULL != mali_group_get_pp_core(disabled_group) && mali_executor_group_is_in_state(disabled_group, EXEC_STATE_DISABLED)) {
2449 mali_executor_group_enable_internal(disabled_group);
2450 core_scaling_delay_up_mask[i]--;
2451 num_pp_cores_to_enable--;
2453 if ((0 == core_scaling_delay_up_mask[i]) || 0 == num_pp_cores_to_enable) {
2462 _mali_osk_wait_queue_wake_up(executor_notify_core_change_wait_queue);
2465 static void mali_executor_change_group_status_disabled(struct mali_group *group)
2467 /* Physical PP group */
2470 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2472 idle = mali_executor_group_is_in_state(group, EXEC_STATE_IDLE);
2473 if (MALI_TRUE == idle) {
2474 mali_executor_change_state_pp_physical(group,
2476 &group_list_idle_count,
2477 &group_list_disabled,
2478 &group_list_disabled_count);
2480 mali_executor_change_state_pp_physical(group,
2481 &group_list_inactive,
2482 &group_list_inactive_count,
2483 &group_list_disabled,
2484 &group_list_disabled_count);
2488 static mali_bool mali_executor_deactivate_list_idle(mali_bool deactivate_idle_group)
2490 mali_bool trigger_pm_update = MALI_FALSE;
2492 if (group_list_idle_count > 0) {
2493 if (mali_executor_has_virtual_group()) {
2495 /* Rejoin virtual group on Mali-450 */
2497 struct mali_group *group;
2498 struct mali_group *temp;
2500 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
2502 struct mali_group, executor_list) {
2503 if (mali_executor_physical_rejoin_virtual(
2505 trigger_pm_update = MALI_TRUE;
2508 } else if (deactivate_idle_group) {
2509 struct mali_group *group;
2510 struct mali_group *temp;
2512 /* Deactivate group on Mali-300/400 */
2514 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
2516 struct mali_group, executor_list) {
2517 if (mali_group_deactivate(group)) {
2518 trigger_pm_update = MALI_TRUE;
2521 /* Move from idle to inactive */
2522 mali_executor_change_state_pp_physical(group,
2524 &group_list_idle_count,
2525 &group_list_inactive,
2526 &group_list_inactive_count);
2531 return trigger_pm_update;