2 * Copyright (C) 2012-2015 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 mali_bool mali_executor_is_suspended(void *data);
125 static mali_bool mali_executor_is_working(void);
126 static void mali_executor_disable_empty_virtual(void);
127 static mali_bool mali_executor_physical_rejoin_virtual(struct mali_group *group);
128 static mali_bool mali_executor_has_virtual_group(void);
129 static mali_bool mali_executor_virtual_group_is_usable(void);
130 static void mali_executor_schedule(void);
131 static void mali_executor_wq_schedule(void *arg);
132 static void mali_executor_send_gp_oom_to_user(struct mali_gp_job *job, u32 added_size);
133 static void mali_executor_complete_group(struct mali_group *group,
135 struct mali_gp_job **gp_job_done,
136 struct mali_pp_job **pp_job_done);
137 static void mali_executor_change_state_pp_physical(struct mali_group *group,
138 _mali_osk_list_t *old_list,
140 _mali_osk_list_t *new_list,
142 static mali_bool mali_executor_group_is_in_state(struct mali_group *group,
143 enum mali_executor_state_t state);
145 static void mali_executor_group_enable_internal(struct mali_group *group);
146 static void mali_executor_group_disable_internal(struct mali_group *group);
147 static void mali_executor_core_scale(unsigned int target_core_nr);
148 static void mali_executor_core_scale_in_group_complete(struct mali_group *group);
149 static void mali_executor_notify_core_change(u32 num_cores);
150 static void mali_executor_wq_notify_core_change(void *arg);
151 static void mali_executor_change_group_status_disabled(struct mali_group *group);
152 static mali_bool mali_executor_deactivate_list_idle(mali_bool deactivate_idle_group);
153 static void mali_executor_set_state_pp_physical(struct mali_group *group,
154 _mali_osk_list_t *new_list,
158 * ---------- Actual implementation ----------
161 _mali_osk_errcode_t mali_executor_initialize(void)
163 mali_executor_lock_obj = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_EXECUTOR);
164 if (NULL == mali_executor_lock_obj) {
165 mali_executor_terminate();
166 return _MALI_OSK_ERR_NOMEM;
169 executor_wq_high_pri = _mali_osk_wq_create_work_high_pri(mali_executor_wq_schedule, NULL);
170 if (NULL == executor_wq_high_pri) {
171 mali_executor_terminate();
172 return _MALI_OSK_ERR_NOMEM;
175 executor_working_wait_queue = _mali_osk_wait_queue_init();
176 if (NULL == executor_working_wait_queue) {
177 mali_executor_terminate();
178 return _MALI_OSK_ERR_NOMEM;
181 executor_wq_notify_core_change = _mali_osk_wq_create_work(mali_executor_wq_notify_core_change, NULL);
182 if (NULL == executor_wq_notify_core_change) {
183 mali_executor_terminate();
184 return _MALI_OSK_ERR_NOMEM;
187 executor_notify_core_change_wait_queue = _mali_osk_wait_queue_init();
188 if (NULL == executor_notify_core_change_wait_queue) {
189 mali_executor_terminate();
190 return _MALI_OSK_ERR_NOMEM;
193 return _MALI_OSK_ERR_OK;
196 void mali_executor_terminate(void)
198 if (NULL != executor_notify_core_change_wait_queue) {
199 _mali_osk_wait_queue_term(executor_notify_core_change_wait_queue);
200 executor_notify_core_change_wait_queue = NULL;
203 if (NULL != executor_wq_notify_core_change) {
204 _mali_osk_wq_delete_work(executor_wq_notify_core_change);
205 executor_wq_notify_core_change = NULL;
208 if (NULL != executor_working_wait_queue) {
209 _mali_osk_wait_queue_term(executor_working_wait_queue);
210 executor_working_wait_queue = NULL;
213 if (NULL != executor_wq_high_pri) {
214 _mali_osk_wq_delete_work(executor_wq_high_pri);
215 executor_wq_high_pri = NULL;
218 if (NULL != mali_executor_lock_obj) {
219 _mali_osk_spinlock_irq_term(mali_executor_lock_obj);
220 mali_executor_lock_obj = NULL;
224 void mali_executor_populate(void)
229 num_groups = mali_group_get_glob_num_groups();
231 /* Do we have a virtual group? */
232 for (i = 0; i < num_groups; i++) {
233 struct mali_group *group = mali_group_get_glob_group(i);
235 if (mali_group_is_virtual(group)) {
236 virtual_group = group;
237 virtual_group_state = EXEC_STATE_INACTIVE;
242 /* Find all the available physical GP and PP cores */
243 for (i = 0; i < num_groups; i++) {
244 struct mali_group *group = mali_group_get_glob_group(i);
247 struct mali_pp_core *pp_core = mali_group_get_pp_core(group);
248 struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
250 if (!mali_group_is_virtual(group)) {
251 if (NULL != pp_core) {
252 if (0 == pp_version) {
253 /* Retrieve PP version from the first available PP core */
254 pp_version = mali_pp_core_get_version(pp_core);
257 if (NULL != virtual_group) {
258 mali_executor_lock();
259 mali_group_add_group(virtual_group, group);
260 mali_executor_unlock();
262 _mali_osk_list_add(&group->executor_list, &group_list_inactive);
263 group_list_inactive_count++;
266 num_physical_pp_cores_total++;
268 MALI_DEBUG_ASSERT_POINTER(gp_core);
270 if (0 == gp_version) {
271 /* Retrieve GP version */
272 gp_version = mali_gp_core_get_version(gp_core);
276 gp_group_state = EXEC_STATE_INACTIVE;
283 num_physical_pp_cores_enabled = num_physical_pp_cores_total;
286 void mali_executor_depopulate(void)
288 struct mali_group *group;
289 struct mali_group *temp;
291 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != gp_group_state);
293 if (NULL != gp_group) {
294 mali_group_delete(gp_group);
298 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != virtual_group_state);
300 if (NULL != virtual_group) {
301 mali_group_delete(virtual_group);
302 virtual_group = NULL;
305 MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
307 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, executor_list) {
308 mali_group_delete(group);
311 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive, struct mali_group, executor_list) {
312 mali_group_delete(group);
315 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, executor_list) {
316 mali_group_delete(group);
320 void mali_executor_suspend(void)
322 mali_executor_lock();
324 /* Increment the pause_count so that no more jobs will be scheduled */
327 mali_executor_unlock();
329 _mali_osk_wait_queue_wait_event(executor_working_wait_queue,
330 mali_executor_is_suspended, NULL);
333 * mali_executor_complete_XX() leaves jobs in idle state.
334 * deactivate option is used when we are going to power down
335 * the entire GPU (OS suspend) and want a consistent SW vs HW
338 mali_executor_lock();
340 mali_executor_deactivate_list_idle(MALI_TRUE);
343 * The following steps are used to deactive all of activated
344 * (MALI_GROUP_STATE_ACTIVE) and activating (MALI_GROUP
345 * _STAET_ACTIVATION_PENDING) groups, to make sure the variable
346 * pd_mask_wanted is equal with 0. */
347 if (MALI_GROUP_STATE_INACTIVE != mali_group_get_state(gp_group)) {
348 gp_group_state = EXEC_STATE_INACTIVE;
349 mali_group_deactivate(gp_group);
352 if (mali_executor_has_virtual_group()) {
353 if (MALI_GROUP_STATE_INACTIVE
354 != mali_group_get_state(virtual_group)) {
355 virtual_group_state = EXEC_STATE_INACTIVE;
356 mali_group_deactivate(virtual_group);
360 if (0 < group_list_inactive_count) {
361 struct mali_group *group;
362 struct mali_group *temp;
364 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
365 &group_list_inactive,
366 struct mali_group, executor_list) {
367 if (MALI_GROUP_STATE_ACTIVATION_PENDING
368 == mali_group_get_state(group)) {
369 mali_group_deactivate(group);
373 * On mali-450 platform, we may have physical group in the group inactive
374 * list, and its state is MALI_GROUP_STATE_ACTIVATION_PENDING, so we only
375 * deactivate it is not enough, we still also need add it back to virtual group.
376 * And now, virtual group must be in INACTIVE state, so it's safe to add
377 * physical group to virtual group at this point.
379 if (NULL != virtual_group) {
380 _mali_osk_list_delinit(&group->executor_list);
381 group_list_inactive_count--;
383 mali_group_add_group(virtual_group, group);
388 mali_executor_unlock();
391 void mali_executor_resume(void)
393 mali_executor_lock();
395 /* Decrement pause_count to allow scheduling again (if it reaches 0) */
397 if (0 == pause_count) {
398 mali_executor_schedule();
401 mali_executor_unlock();
404 u32 mali_executor_get_num_cores_total(void)
406 return num_physical_pp_cores_total;
409 u32 mali_executor_get_num_cores_enabled(void)
411 return num_physical_pp_cores_enabled;
414 struct mali_pp_core *mali_executor_get_virtual_pp(void)
416 MALI_DEBUG_ASSERT_POINTER(virtual_group);
417 MALI_DEBUG_ASSERT_POINTER(virtual_group->pp_core);
418 return virtual_group->pp_core;
421 struct mali_group *mali_executor_get_virtual_group(void)
423 return virtual_group;
426 void mali_executor_zap_all_active(struct mali_session_data *session)
428 struct mali_group *group;
429 struct mali_group *temp;
432 mali_executor_lock();
435 * This function is a bit complicated because
436 * mali_group_zap_session() can fail. This only happens because the
437 * group is in an unhandled page fault status.
438 * We need to make sure this page fault is handled before we return,
439 * so that we know every single outstanding MMU transactions have
440 * completed. This will allow caller to safely remove physical pages
441 * when we have returned.
444 MALI_DEBUG_ASSERT(NULL != gp_group);
445 ret = mali_group_zap_session(gp_group, session);
446 if (MALI_FALSE == ret) {
447 struct mali_gp_job *gp_job = NULL;
449 mali_executor_complete_group(gp_group, MALI_FALSE, &gp_job, NULL);
451 MALI_DEBUG_ASSERT_POINTER(gp_job);
453 /* GP job completed, make sure it is freed */
454 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
455 MALI_TRUE, MALI_TRUE);
458 if (mali_executor_has_virtual_group()) {
459 ret = mali_group_zap_session(virtual_group, session);
460 if (MALI_FALSE == ret) {
461 struct mali_pp_job *pp_job = NULL;
463 mali_executor_complete_group(virtual_group, MALI_FALSE, NULL, &pp_job);
465 if (NULL != pp_job) {
466 /* PP job completed, make sure it is freed */
467 mali_scheduler_complete_pp_job(pp_job, 0,
468 MALI_FALSE, MALI_TRUE);
473 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working,
474 struct mali_group, executor_list) {
475 ret = mali_group_zap_session(group, session);
476 if (MALI_FALSE == ret) {
477 ret = mali_group_zap_session(group, session);
478 if (MALI_FALSE == ret) {
479 struct mali_pp_job *pp_job = NULL;
481 mali_executor_complete_group(group, MALI_FALSE, NULL, &pp_job);
483 if (NULL != pp_job) {
484 /* PP job completed, free it */
485 mali_scheduler_complete_pp_job(pp_job,
493 mali_executor_unlock();
496 void mali_executor_schedule_from_mask(mali_scheduler_mask mask, mali_bool deferred_schedule)
498 if (MALI_SCHEDULER_MASK_EMPTY != mask) {
499 if (MALI_TRUE == deferred_schedule) {
500 _mali_osk_wq_schedule_work_high_pri(executor_wq_high_pri);
502 /* Schedule from this thread*/
503 mali_executor_lock();
504 mali_executor_schedule();
505 mali_executor_unlock();
510 _mali_osk_errcode_t mali_executor_interrupt_gp(struct mali_group *group,
511 mali_bool in_upper_half)
513 enum mali_interrupt_result int_result;
514 mali_bool time_out = MALI_FALSE;
516 MALI_DEBUG_PRINT(4, ("Executor: GP interrupt from %s in %s half\n",
517 mali_group_core_description(group),
518 in_upper_half ? "upper" : "bottom"));
520 mali_executor_lock();
521 if (!mali_group_is_working(group)) {
522 /* Not working, so nothing to do */
523 mali_executor_unlock();
524 return _MALI_OSK_ERR_FAULT;
527 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
528 MALI_DEBUG_ASSERT(mali_group_is_working(group));
530 if (mali_group_has_timed_out(group)) {
531 int_result = MALI_INTERRUPT_RESULT_ERROR;
532 time_out = MALI_TRUE;
533 MALI_PRINT(("Executor GP: Job %d Timeout on %s\n",
534 mali_gp_job_get_id(group->gp_running_job),
535 mali_group_core_description(group)));
537 int_result = mali_group_get_interrupt_result_gp(group);
538 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
539 mali_executor_unlock();
540 return _MALI_OSK_ERR_FAULT;
544 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
545 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
546 /* No interrupts signalled, so nothing to do */
547 mali_executor_unlock();
548 return _MALI_OSK_ERR_FAULT;
551 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_NONE != int_result);
554 mali_group_mask_all_interrupts_gp(group);
556 if (MALI_INTERRUPT_RESULT_SUCCESS_VS == int_result) {
557 if (mali_group_gp_is_active(group)) {
558 /* Only VS completed so far, while PLBU is still active */
560 /* Enable all but the current interrupt */
561 mali_group_enable_interrupts_gp(group, int_result);
563 mali_executor_unlock();
564 return _MALI_OSK_ERR_OK;
566 } else if (MALI_INTERRUPT_RESULT_SUCCESS_PLBU == int_result) {
567 if (mali_group_gp_is_active(group)) {
568 /* Only PLBU completed so far, while VS is still active */
570 /* Enable all but the current interrupt */
571 mali_group_enable_interrupts_gp(group, int_result);
573 mali_executor_unlock();
574 return _MALI_OSK_ERR_OK;
576 } else if (MALI_INTERRUPT_RESULT_OOM == int_result) {
578 mali_executor_unlock();
580 mali_group_schedule_oom_work_handler(group);
582 return _MALI_OSK_ERR_OK;
585 /*Add for voltage scan function*/
586 if (MALI_INTERRUPT_RESULT_ERROR == int_result)
589 /* We should now have a real interrupt to handle */
591 MALI_DEBUG_PRINT(4, ("Executor: Group %s completed with %s\n",
592 mali_group_core_description(group),
593 (MALI_INTERRUPT_RESULT_ERROR == int_result) ?
594 "ERROR" : "success"));
596 if (in_upper_half && MALI_INTERRUPT_RESULT_ERROR == int_result) {
597 /* Don't bother to do processing of errors in upper half */
598 mali_executor_unlock();
600 if (MALI_FALSE == time_out) {
601 mali_group_schedule_bottom_half_gp(group);
604 struct mali_gp_job *job;
607 if (MALI_TRUE == time_out) {
608 mali_group_dump_status(group);
611 success = (int_result != MALI_INTERRUPT_RESULT_ERROR) ?
612 MALI_TRUE : MALI_FALSE;
614 mali_executor_complete_group(group, success, &job, NULL);
616 mali_executor_unlock();
618 /* GP jobs always fully complete */
619 MALI_DEBUG_ASSERT(NULL != job);
621 /* This will notify user space and close the job object */
622 mali_scheduler_complete_gp_job(job, success,
623 MALI_TRUE, MALI_TRUE);
626 return _MALI_OSK_ERR_OK;
629 _mali_osk_errcode_t mali_executor_interrupt_pp(struct mali_group *group,
630 mali_bool in_upper_half)
632 enum mali_interrupt_result int_result;
633 mali_bool time_out = MALI_FALSE;
635 MALI_DEBUG_PRINT(4, ("Executor: PP interrupt from %s in %s half\n",
636 mali_group_core_description(group),
637 in_upper_half ? "upper" : "bottom"));
639 mali_executor_lock();
641 if (!mali_group_is_working(group)) {
642 /* Not working, so nothing to do */
643 mali_executor_unlock();
644 return _MALI_OSK_ERR_FAULT;
648 if (mali_group_is_in_virtual(group)) {
649 /* Child groups should never handle PP interrupts */
650 MALI_DEBUG_ASSERT(!mali_group_has_timed_out(group));
651 mali_executor_unlock();
652 return _MALI_OSK_ERR_FAULT;
655 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
656 MALI_DEBUG_ASSERT(mali_group_is_working(group));
657 MALI_DEBUG_ASSERT(!mali_group_is_in_virtual(group));
659 if (mali_group_has_timed_out(group)) {
660 int_result = MALI_INTERRUPT_RESULT_ERROR;
661 time_out = MALI_TRUE;
662 MALI_PRINT(("Executor PP: Job %d Timeout on %s\n",
663 mali_pp_job_get_id(group->pp_running_job),
664 mali_group_core_description(group)));
666 int_result = mali_group_get_interrupt_result_pp(group);
667 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
668 mali_executor_unlock();
669 return _MALI_OSK_ERR_FAULT;
673 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
674 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
675 /* No interrupts signalled, so nothing to do */
676 mali_executor_unlock();
677 return _MALI_OSK_ERR_FAULT;
678 } else if (MALI_INTERRUPT_RESULT_SUCCESS == int_result) {
679 if (mali_group_is_virtual(group) && mali_group_pp_is_active(group)) {
680 /* Some child groups are still working, so nothing to do right now */
681 mali_executor_unlock();
682 return _MALI_OSK_ERR_FAULT;
686 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_NONE != int_result);
689 /*Add voltage scan function*/
691 if (MALI_INTERRUPT_RESULT_ERROR == int_result)
694 /* We should now have a real interrupt to handle */
696 MALI_DEBUG_PRINT(4, ("Executor: Group %s completed with %s\n",
697 mali_group_core_description(group),
698 (MALI_INTERRUPT_RESULT_ERROR == int_result) ?
699 "ERROR" : "success"));
701 if (in_upper_half && MALI_INTERRUPT_RESULT_ERROR == int_result) {
702 /* Don't bother to do processing of errors in upper half */
703 mali_group_mask_all_interrupts_pp(group);
704 mali_executor_unlock();
706 if (MALI_FALSE == time_out) {
707 mali_group_schedule_bottom_half_pp(group);
710 struct mali_pp_job *job = NULL;
713 if (MALI_TRUE == time_out) {
714 mali_group_dump_status(group);
717 success = (int_result == MALI_INTERRUPT_RESULT_SUCCESS) ?
718 MALI_TRUE : MALI_FALSE;
720 mali_executor_complete_group(group, success, NULL, &job);
722 mali_executor_unlock();
725 /* Notify user space and close the job object */
726 mali_scheduler_complete_pp_job(job,
727 num_physical_pp_cores_total,
728 MALI_TRUE, MALI_TRUE);
732 return _MALI_OSK_ERR_OK;
735 _mali_osk_errcode_t mali_executor_interrupt_mmu(struct mali_group *group,
736 mali_bool in_upper_half)
738 enum mali_interrupt_result int_result;
740 MALI_DEBUG_PRINT(4, ("Executor: MMU interrupt from %s in %s half\n",
741 mali_group_core_description(group),
742 in_upper_half ? "upper" : "bottom"));
744 mali_executor_lock();
745 if (!mali_group_is_working(group)) {
746 /* Not working, so nothing to do */
747 mali_executor_unlock();
748 return _MALI_OSK_ERR_FAULT;
751 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
752 MALI_DEBUG_ASSERT(mali_group_is_working(group));
754 int_result = mali_group_get_interrupt_result_mmu(group);
755 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
756 mali_executor_unlock();
757 return _MALI_OSK_ERR_FAULT;
760 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
761 if (MALI_INTERRUPT_RESULT_NONE == int_result) {
762 /* No interrupts signalled, so nothing to do */
763 mali_executor_unlock();
764 return _MALI_OSK_ERR_FAULT;
767 MALI_DEBUG_ASSERT(MALI_INTERRUPT_RESULT_ERROR == int_result);
770 /* We should now have a real interrupt to handle */
773 /* Don't bother to do processing of errors in upper half */
775 struct mali_group *parent = group->parent_group;
777 mali_mmu_mask_all_interrupts(group->mmu);
779 mali_executor_unlock();
781 if (NULL == parent) {
782 mali_group_schedule_bottom_half_mmu(group);
784 mali_group_schedule_bottom_half_mmu(parent);
788 struct mali_gp_job *gp_job = NULL;
789 struct mali_pp_job *pp_job = NULL;
793 u32 fault_address = mali_mmu_get_page_fault_addr(group->mmu);
794 u32 status = mali_mmu_get_status(group->mmu);
795 MALI_DEBUG_PRINT(2, ("Executor: Mali page fault detected at 0x%x from bus id %d of type %s on %s\n",
796 (void *)(uintptr_t)fault_address,
797 (status >> 6) & 0x1F,
798 (status & 32) ? "write" : "read",
799 group->mmu->hw_core.description));
800 MALI_DEBUG_PRINT(3, ("Executor: MMU rawstat = 0x%08X, MMU status = 0x%08X\n",
801 mali_mmu_get_rawstat(group->mmu), status));
802 mali_mmu_pagedir_diag(mali_session_get_page_directory(group->session), fault_address);
805 mali_executor_complete_group(group, MALI_FALSE, &gp_job, &pp_job);
807 mali_executor_unlock();
809 if (NULL != gp_job) {
810 MALI_DEBUG_ASSERT(NULL == pp_job);
812 /* Notify user space and close the job object */
813 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
814 MALI_TRUE, MALI_TRUE);
815 } else if (NULL != pp_job) {
816 MALI_DEBUG_ASSERT(NULL == gp_job);
818 /* Notify user space and close the job object */
819 mali_scheduler_complete_pp_job(pp_job,
820 num_physical_pp_cores_total,
821 MALI_TRUE, MALI_TRUE);
825 return _MALI_OSK_ERR_OK;
828 void mali_executor_group_oom(struct mali_group *group)
830 struct mali_gp_job *job = NULL;
831 MALI_DEBUG_ASSERT_POINTER(group);
832 MALI_DEBUG_ASSERT_POINTER(group->gp_core);
833 MALI_DEBUG_ASSERT_POINTER(group->mmu);
835 mali_executor_lock();
837 job = mali_group_get_running_gp_job(group);
839 MALI_DEBUG_ASSERT_POINTER(job);
841 #if defined(CONFIG_MALI400_PROFILING)
842 /* Give group a chance to generate a SUSPEND event */
843 mali_group_oom(group);
846 mali_gp_job_set_current_heap_addr(job, mali_gp_read_plbu_alloc_start_addr(group->gp_core));
848 mali_executor_unlock();
850 if (_MALI_OSK_ERR_OK == mali_mem_add_mem_size(job->session, job->heap_base_addr, job->heap_grow_size)) {
851 _mali_osk_notification_t *new_notification = NULL;
853 new_notification = _mali_osk_notification_create(
854 _MALI_NOTIFICATION_GP_STALLED,
855 sizeof(_mali_uk_gp_job_suspended_s));
857 /* resume job with new heap,
858 * This will also re-enable interrupts
860 mali_executor_lock();
862 mali_executor_send_gp_oom_to_user(job, job->heap_grow_size);
864 if (NULL != new_notification) {
866 mali_gp_job_set_oom_notification(job, new_notification);
868 mali_group_resume_gp_with_new_heap(group, mali_gp_job_get_id(job),
869 job->heap_current_addr,
870 job->heap_current_addr + job->heap_grow_size);
872 mali_executor_unlock();
874 mali_executor_lock();
875 mali_executor_send_gp_oom_to_user(job, 0);
876 mali_executor_unlock();
881 void mali_executor_group_power_up(struct mali_group *groups[], u32 num_groups)
884 mali_bool child_groups_activated = MALI_FALSE;
885 mali_bool do_schedule = MALI_FALSE;
887 u32 num_activated = 0;
890 MALI_DEBUG_ASSERT_POINTER(groups);
891 MALI_DEBUG_ASSERT(0 < num_groups);
893 mali_executor_lock();
895 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups\n", num_groups));
897 for (i = 0; i < num_groups; i++) {
898 MALI_DEBUG_PRINT(3, ("Executor: powering up group %s\n",
899 mali_group_core_description(groups[i])));
901 mali_group_power_up(groups[i]);
903 if ((MALI_GROUP_STATE_ACTIVATION_PENDING != mali_group_get_state(groups[i]) ||
904 (MALI_TRUE != mali_executor_group_is_in_state(groups[i], EXEC_STATE_INACTIVE)))) {
905 /* nothing more to do for this group */
909 MALI_DEBUG_PRINT(3, ("Executor: activating group %s\n",
910 mali_group_core_description(groups[i])));
916 if (mali_group_is_in_virtual(groups[i])) {
918 * At least one child group of virtual group is powered on.
920 child_groups_activated = MALI_TRUE;
921 } else if (MALI_FALSE == mali_group_is_virtual(groups[i])) {
922 /* Set gp and pp not in virtual to active. */
923 mali_group_set_active(groups[i]);
926 /* Move group from inactive to idle list */
927 if (groups[i] == gp_group) {
928 MALI_DEBUG_ASSERT(EXEC_STATE_INACTIVE ==
930 gp_group_state = EXEC_STATE_IDLE;
931 } else if (MALI_FALSE == mali_group_is_in_virtual(groups[i])
932 && MALI_FALSE == mali_group_is_virtual(groups[i])) {
933 MALI_DEBUG_ASSERT(MALI_TRUE == mali_executor_group_is_in_state(groups[i],
934 EXEC_STATE_INACTIVE));
936 mali_executor_change_state_pp_physical(groups[i],
937 &group_list_inactive,
938 &group_list_inactive_count,
940 &group_list_idle_count);
943 do_schedule = MALI_TRUE;
946 if (mali_executor_has_virtual_group() &&
947 MALI_TRUE == child_groups_activated &&
948 MALI_GROUP_STATE_ACTIVATION_PENDING ==
949 mali_group_get_state(virtual_group)) {
951 * Try to active virtual group while it may be not sucessful every time,
952 * because there is one situation that not all of child groups are powered on
953 * in one time and virtual group is in activation pending state.
955 if (mali_group_set_active(virtual_group)) {
956 /* Move group from inactive to idle */
957 MALI_DEBUG_ASSERT(EXEC_STATE_INACTIVE ==
958 virtual_group_state);
959 virtual_group_state = EXEC_STATE_IDLE;
961 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated, 1 virtual activated.\n", num_groups, num_activated));
963 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated\n", num_groups, num_activated));
966 MALI_DEBUG_PRINT(3, ("Executor: powering up %u groups completed, %u physical activated\n", num_groups, num_activated));
969 if (MALI_TRUE == do_schedule) {
970 /* Trigger a schedule */
971 mali_executor_schedule();
974 mali_executor_unlock();
977 void mali_executor_group_power_down(struct mali_group *groups[],
982 MALI_DEBUG_ASSERT_POINTER(groups);
983 MALI_DEBUG_ASSERT(0 < num_groups);
985 mali_executor_lock();
987 MALI_DEBUG_PRINT(3, ("Executor: powering down %u groups\n", num_groups));
989 for (i = 0; i < num_groups; i++) {
990 /* Groups must be either disabled or inactive. while for virtual group,
991 * it maybe in empty state, because when we meet pm_runtime_suspend,
992 * virtual group could be powered off, and before we acquire mali_executor_lock,
993 * we must release mali_pm_state_lock, if there is a new physical job was queued,
994 * all of physical groups in virtual group could be pulled out, so we only can
995 * powered down an empty virtual group. Those physical groups will be powered
996 * up in following pm_runtime_resume callback function.
998 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(groups[i],
999 EXEC_STATE_DISABLED) ||
1000 mali_executor_group_is_in_state(groups[i],
1001 EXEC_STATE_INACTIVE) ||
1002 mali_executor_group_is_in_state(groups[i],
1005 MALI_DEBUG_PRINT(3, ("Executor: powering down group %s\n",
1006 mali_group_core_description(groups[i])));
1008 mali_group_power_down(groups[i]);
1011 MALI_DEBUG_PRINT(3, ("Executor: powering down %u groups completed\n", num_groups));
1013 mali_executor_unlock();
1016 void mali_executor_abort_session(struct mali_session_data *session)
1018 struct mali_group *group;
1019 struct mali_group *tmp_group;
1021 MALI_DEBUG_ASSERT_POINTER(session);
1022 MALI_DEBUG_ASSERT(session->is_aborting);
1025 ("Executor: Aborting all jobs from session 0x%08X.\n",
1028 mali_executor_lock();
1030 if (mali_group_get_session(gp_group) == session) {
1031 if (EXEC_STATE_WORKING == gp_group_state) {
1032 struct mali_gp_job *gp_job = NULL;
1034 mali_executor_complete_group(gp_group, MALI_FALSE, &gp_job, NULL);
1036 MALI_DEBUG_ASSERT_POINTER(gp_job);
1038 /* GP job completed, make sure it is freed */
1039 mali_scheduler_complete_gp_job(gp_job, MALI_FALSE,
1040 MALI_FALSE, MALI_TRUE);
1042 /* Same session, but not working, so just clear it */
1043 mali_group_clear_session(gp_group);
1047 if (mali_executor_has_virtual_group()) {
1048 if (EXEC_STATE_WORKING == virtual_group_state
1049 && mali_group_get_session(virtual_group) == session) {
1050 struct mali_pp_job *pp_job = NULL;
1052 mali_executor_complete_group(virtual_group, MALI_FALSE, NULL, &pp_job);
1054 if (NULL != pp_job) {
1055 /* PP job completed, make sure it is freed */
1056 mali_scheduler_complete_pp_job(pp_job, 0,
1057 MALI_FALSE, MALI_TRUE);
1062 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_working,
1063 struct mali_group, executor_list) {
1064 if (mali_group_get_session(group) == session) {
1065 struct mali_pp_job *pp_job = NULL;
1067 mali_executor_complete_group(group, MALI_FALSE, NULL, &pp_job);
1069 if (NULL != pp_job) {
1070 /* PP job completed, make sure it is freed */
1071 mali_scheduler_complete_pp_job(pp_job, 0,
1072 MALI_FALSE, MALI_TRUE);
1077 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_idle, struct mali_group, executor_list) {
1078 mali_group_clear_session(group);
1081 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_inactive, struct mali_group, executor_list) {
1082 mali_group_clear_session(group);
1085 _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_disabled, struct mali_group, executor_list) {
1086 mali_group_clear_session(group);
1089 mali_executor_unlock();
1093 void mali_executor_core_scaling_enable(void)
1095 /* PS: Core scaling is by default enabled */
1096 core_scaling_enabled = MALI_TRUE;
1099 void mali_executor_core_scaling_disable(void)
1101 core_scaling_enabled = MALI_FALSE;
1104 mali_bool mali_executor_core_scaling_is_enabled(void)
1106 return core_scaling_enabled;
1109 void mali_executor_group_enable(struct mali_group *group)
1111 MALI_DEBUG_ASSERT_POINTER(group);
1113 mali_executor_lock();
1115 if ((NULL != mali_group_get_gp_core(group) || NULL != mali_group_get_pp_core(group))
1116 && (mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))) {
1117 mali_executor_group_enable_internal(group);
1120 mali_executor_schedule();
1121 mali_executor_unlock();
1123 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1127 * If a physical group is inactive or idle, we should disable it immediately,
1128 * if group is in virtual, and virtual group is idle, disable given physical group in it.
1130 void mali_executor_group_disable(struct mali_group *group)
1132 MALI_DEBUG_ASSERT_POINTER(group);
1134 mali_executor_lock();
1136 if ((NULL != mali_group_get_gp_core(group) || NULL != mali_group_get_pp_core(group))
1137 && (!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))) {
1138 mali_executor_group_disable_internal(group);
1141 mali_executor_schedule();
1142 mali_executor_unlock();
1144 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1147 mali_bool mali_executor_group_is_disabled(struct mali_group *group)
1149 /* NB: This function is not optimized for time critical usage */
1153 MALI_DEBUG_ASSERT_POINTER(group);
1155 mali_executor_lock();
1156 ret = mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED);
1157 mali_executor_unlock();
1162 int mali_executor_set_perf_level(unsigned int target_core_nr, mali_bool override)
1164 if (target_core_nr == num_physical_pp_cores_enabled) return 0;
1165 if (MALI_FALSE == core_scaling_enabled && MALI_FALSE == override) return -EPERM;
1166 if (target_core_nr > num_physical_pp_cores_total) return -EINVAL;
1167 if (0 == target_core_nr) return -EINVAL;
1169 mali_executor_core_scale(target_core_nr);
1171 _mali_osk_wq_schedule_work(executor_wq_notify_core_change);
1176 #if MALI_STATE_TRACKING
1177 u32 mali_executor_dump_state(char *buf, u32 size)
1180 struct mali_group *group;
1181 struct mali_group *temp;
1183 mali_executor_lock();
1185 switch (gp_group_state) {
1186 case EXEC_STATE_INACTIVE:
1187 n += _mali_osk_snprintf(buf + n, size - n,
1188 "GP group is in state INACTIVE\n");
1190 case EXEC_STATE_IDLE:
1191 n += _mali_osk_snprintf(buf + n, size - n,
1192 "GP group is in state IDLE\n");
1194 case EXEC_STATE_WORKING:
1195 n += _mali_osk_snprintf(buf + n, size - n,
1196 "GP group is in state WORKING\n");
1199 n += _mali_osk_snprintf(buf + n, size - n,
1200 "GP group is in unknown/illegal state %u\n",
1205 n += mali_group_dump_state(gp_group, buf + n, size - n);
1207 n += _mali_osk_snprintf(buf + n, size - n,
1208 "Physical PP groups in WORKING state (count = %u):\n",
1209 group_list_working_count);
1211 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, executor_list) {
1212 n += mali_group_dump_state(group, buf + n, size - n);
1215 n += _mali_osk_snprintf(buf + n, size - n,
1216 "Physical PP groups in IDLE state (count = %u):\n",
1217 group_list_idle_count);
1219 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, executor_list) {
1220 n += mali_group_dump_state(group, buf + n, size - n);
1223 n += _mali_osk_snprintf(buf + n, size - n,
1224 "Physical PP groups in INACTIVE state (count = %u):\n",
1225 group_list_inactive_count);
1227 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive, struct mali_group, executor_list) {
1228 n += mali_group_dump_state(group, buf + n, size - n);
1231 n += _mali_osk_snprintf(buf + n, size - n,
1232 "Physical PP groups in DISABLED state (count = %u):\n",
1233 group_list_disabled_count);
1235 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, executor_list) {
1236 n += mali_group_dump_state(group, buf + n, size - n);
1239 if (mali_executor_has_virtual_group()) {
1240 switch (virtual_group_state) {
1241 case EXEC_STATE_EMPTY:
1242 n += _mali_osk_snprintf(buf + n, size - n,
1243 "Virtual PP group is in state EMPTY\n");
1245 case EXEC_STATE_INACTIVE:
1246 n += _mali_osk_snprintf(buf + n, size - n,
1247 "Virtual PP group is in state INACTIVE\n");
1249 case EXEC_STATE_IDLE:
1250 n += _mali_osk_snprintf(buf + n, size - n,
1251 "Virtual PP group is in state IDLE\n");
1253 case EXEC_STATE_WORKING:
1254 n += _mali_osk_snprintf(buf + n, size - n,
1255 "Virtual PP group is in state WORKING\n");
1258 n += _mali_osk_snprintf(buf + n, size - n,
1259 "Virtual PP group is in unknown/illegal state %u\n",
1260 virtual_group_state);
1264 n += mali_group_dump_state(virtual_group, buf + n, size - n);
1267 mali_executor_unlock();
1269 n += _mali_osk_snprintf(buf + n, size - n, "\n");
1275 _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args)
1277 MALI_DEBUG_ASSERT_POINTER(args);
1278 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1279 args->number_of_total_cores = num_physical_pp_cores_total;
1280 args->number_of_enabled_cores = num_physical_pp_cores_enabled;
1281 return _MALI_OSK_ERR_OK;
1284 _mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args)
1286 MALI_DEBUG_ASSERT_POINTER(args);
1287 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1288 args->version = pp_version;
1289 return _MALI_OSK_ERR_OK;
1292 _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args)
1294 MALI_DEBUG_ASSERT_POINTER(args);
1295 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1296 args->number_of_cores = 1;
1297 return _MALI_OSK_ERR_OK;
1300 _mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args)
1302 MALI_DEBUG_ASSERT_POINTER(args);
1303 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1304 args->version = gp_version;
1305 return _MALI_OSK_ERR_OK;
1308 _mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args)
1310 struct mali_session_data *session;
1311 struct mali_gp_job *job;
1313 MALI_DEBUG_ASSERT_POINTER(args);
1314 MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx);
1316 session = (struct mali_session_data *)(uintptr_t)args->ctx;
1318 if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) {
1319 _mali_osk_notification_t *new_notification = NULL;
1321 new_notification = _mali_osk_notification_create(
1322 _MALI_NOTIFICATION_GP_STALLED,
1323 sizeof(_mali_uk_gp_job_suspended_s));
1325 if (NULL != new_notification) {
1326 MALI_DEBUG_PRINT(3, ("Executor: Resuming job %u with new heap; 0x%08X - 0x%08X\n",
1327 args->cookie, args->arguments[0], args->arguments[1]));
1329 mali_executor_lock();
1331 /* Resume the job in question if it is still running */
1332 job = mali_group_get_running_gp_job(gp_group);
1334 args->cookie == mali_gp_job_get_id(job) &&
1335 session == mali_gp_job_get_session(job)) {
1337 * Correct job is running, resume with new heap
1340 mali_gp_job_set_oom_notification(job,
1343 /* This will also re-enable interrupts */
1344 mali_group_resume_gp_with_new_heap(gp_group,
1347 args->arguments[1]);
1349 job->heap_base_addr = args->arguments[0];
1350 job->heap_current_addr = args->arguments[0];
1352 mali_executor_unlock();
1353 return _MALI_OSK_ERR_OK;
1355 MALI_PRINT_ERROR(("Executor: Unable to resume, GP job no longer running.\n"));
1357 _mali_osk_notification_delete(new_notification);
1359 mali_executor_unlock();
1360 return _MALI_OSK_ERR_FAULT;
1363 MALI_PRINT_ERROR(("Executor: Failed to allocate notification object. Will abort GP job.\n"));
1366 MALI_DEBUG_PRINT(2, ("Executor: Aborting job %u, no new heap provided\n", args->cookie));
1369 mali_executor_lock();
1371 /* Abort the job in question if it is still running */
1372 job = mali_group_get_running_gp_job(gp_group);
1374 args->cookie == mali_gp_job_get_id(job) &&
1375 session == mali_gp_job_get_session(job)) {
1376 /* Correct job is still running */
1377 struct mali_gp_job *job_done = NULL;
1379 mali_executor_complete_group(gp_group, MALI_FALSE, &job_done, NULL);
1381 /* The same job should have completed */
1382 MALI_DEBUG_ASSERT(job_done == job);
1384 /* GP job completed, make sure it is freed */
1385 mali_scheduler_complete_gp_job(job_done, MALI_FALSE,
1386 MALI_TRUE, MALI_TRUE);
1389 mali_executor_unlock();
1390 return _MALI_OSK_ERR_FAULT;
1395 * ---------- Implementation of static functions ----------
1398 void mali_executor_lock(void)
1400 _mali_osk_spinlock_irq_lock(mali_executor_lock_obj);
1401 MALI_DEBUG_PRINT(5, ("Executor: lock taken\n"));
1404 void mali_executor_unlock(void)
1406 MALI_DEBUG_PRINT(5, ("Executor: Releasing lock\n"));
1407 _mali_osk_spinlock_irq_unlock(mali_executor_lock_obj);
1410 static mali_bool mali_executor_is_suspended(void *data)
1414 /* This callback does not use the data pointer. */
1417 mali_executor_lock();
1419 ret = pause_count > 0 && !mali_executor_is_working();
1421 mali_executor_unlock();
1426 static mali_bool mali_executor_is_working()
1428 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1430 return (0 != group_list_working_count ||
1431 EXEC_STATE_WORKING == gp_group_state ||
1432 EXEC_STATE_WORKING == virtual_group_state);
1435 static void mali_executor_disable_empty_virtual(void)
1437 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1438 MALI_DEBUG_ASSERT(virtual_group_state != EXEC_STATE_EMPTY);
1439 MALI_DEBUG_ASSERT(virtual_group_state != EXEC_STATE_WORKING);
1441 if (mali_group_is_empty(virtual_group)) {
1442 virtual_group_state = EXEC_STATE_EMPTY;
1446 static mali_bool mali_executor_physical_rejoin_virtual(struct mali_group *group)
1448 mali_bool trigger_pm_update = MALI_FALSE;
1450 MALI_DEBUG_ASSERT_POINTER(group);
1451 /* Only rejoining after job has completed (still active) */
1452 MALI_DEBUG_ASSERT(MALI_GROUP_STATE_ACTIVE ==
1453 mali_group_get_state(group));
1454 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1455 MALI_DEBUG_ASSERT(MALI_TRUE == mali_executor_has_virtual_group());
1456 MALI_DEBUG_ASSERT(MALI_FALSE == mali_group_is_virtual(group));
1458 /* Make sure group and virtual group have same status */
1460 if (MALI_GROUP_STATE_INACTIVE == mali_group_get_state(virtual_group)) {
1461 if (mali_group_deactivate(group)) {
1462 trigger_pm_update = MALI_TRUE;
1465 if (virtual_group_state == EXEC_STATE_EMPTY) {
1466 virtual_group_state = EXEC_STATE_INACTIVE;
1468 } else if (MALI_GROUP_STATE_ACTIVATION_PENDING ==
1469 mali_group_get_state(virtual_group)) {
1471 * Activation is pending for virtual group, leave
1472 * this child group as active.
1474 if (virtual_group_state == EXEC_STATE_EMPTY) {
1475 virtual_group_state = EXEC_STATE_INACTIVE;
1478 MALI_DEBUG_ASSERT(MALI_GROUP_STATE_ACTIVE ==
1479 mali_group_get_state(virtual_group));
1481 if (virtual_group_state == EXEC_STATE_EMPTY) {
1482 virtual_group_state = EXEC_STATE_IDLE;
1486 /* Remove group from idle list */
1487 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(group,
1489 _mali_osk_list_delinit(&group->executor_list);
1490 group_list_idle_count--;
1493 * And finally rejoin the virtual group
1494 * group will start working on same job as virtual_group,
1495 * if virtual_group is working on a job
1497 mali_group_add_group(virtual_group, group);
1499 return trigger_pm_update;
1502 static mali_bool mali_executor_has_virtual_group(void)
1504 #if (defined(CONFIG_MALI450) || defined(CONFIG_MALI470))
1505 return (NULL != virtual_group) ? MALI_TRUE : MALI_FALSE;
1508 #endif /* (defined(CONFIG_MALI450) || defined(CONFIG_MALI470)) */
1511 static mali_bool mali_executor_virtual_group_is_usable(void)
1513 #if (defined(CONFIG_MALI450) || defined(CONFIG_MALI470))
1514 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1515 return ((EXEC_STATE_INACTIVE == virtual_group_state ||
1516 EXEC_STATE_IDLE == virtual_group_state) && (virtual_group->state != MALI_GROUP_STATE_ACTIVATION_PENDING)) ?
1517 MALI_TRUE : MALI_FALSE;
1520 #endif /* (defined(CONFIG_MALI450) || defined(CONFIG_MALI470)) */
1523 static mali_bool mali_executor_tackle_gp_bound(void)
1525 struct mali_pp_job *job;
1527 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1529 job = mali_scheduler_job_pp_physical_peek();
1531 if (NULL != job && MALI_TRUE == mali_is_mali400()) {
1532 if (0 < group_list_working_count &&
1533 mali_pp_job_is_large_and_unstarted(job)) {
1542 * This is where jobs are actually started.
1544 static void mali_executor_schedule(void)
1547 u32 num_physical_needed = 0;
1548 u32 num_physical_to_process = 0;
1549 mali_bool trigger_pm_update = MALI_FALSE;
1550 mali_bool deactivate_idle_group = MALI_TRUE;
1552 /* Physical groups + jobs to start in this function */
1553 struct mali_group *groups_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1554 struct mali_pp_job *jobs_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1555 u32 sub_jobs_to_start[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS];
1556 int num_jobs_to_start = 0;
1558 /* Virtual job to start in this function */
1559 struct mali_pp_job *virtual_job_to_start = NULL;
1561 /* GP job to start in this function */
1562 struct mali_gp_job *gp_job_to_start = NULL;
1564 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1566 if (pause_count > 0) {
1567 /* Execution is suspended, don't schedule any jobs. */
1571 /* Lock needed in order to safely handle the job queues */
1572 mali_scheduler_lock();
1574 /* 1. Activate gp firstly if have gp job queued. */
1575 if (EXEC_STATE_INACTIVE == gp_group_state &&
1576 0 < mali_scheduler_job_gp_count()) {
1578 enum mali_group_state state =
1579 mali_group_activate(gp_group);
1580 if (MALI_GROUP_STATE_ACTIVE == state) {
1581 /* Set GP group state to idle */
1582 gp_group_state = EXEC_STATE_IDLE;
1584 trigger_pm_update = MALI_TRUE;
1588 /* 2. Prepare as many physical groups as needed/possible */
1590 num_physical_needed = mali_scheduler_job_physical_head_count();
1592 /* On mali-450 platform, we don't need to enter in this block frequently. */
1593 if (0 < num_physical_needed) {
1595 if (num_physical_needed <= group_list_idle_count) {
1596 /* We have enough groups on idle list already */
1597 num_physical_to_process = num_physical_needed;
1598 num_physical_needed = 0;
1600 /* We need to get a hold of some more groups */
1601 num_physical_to_process = group_list_idle_count;
1602 num_physical_needed -= group_list_idle_count;
1605 if (0 < num_physical_needed) {
1607 /* 2.1. Activate groups which are inactive */
1609 struct mali_group *group;
1610 struct mali_group *temp;
1612 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive,
1613 struct mali_group, executor_list) {
1614 enum mali_group_state state =
1615 mali_group_activate(group);
1616 if (MALI_GROUP_STATE_ACTIVE == state) {
1617 /* Move from inactive to idle */
1618 mali_executor_change_state_pp_physical(group,
1619 &group_list_inactive,
1620 &group_list_inactive_count,
1622 &group_list_idle_count);
1623 num_physical_to_process++;
1625 trigger_pm_update = MALI_TRUE;
1628 num_physical_needed--;
1629 if (0 == num_physical_needed) {
1630 /* We have activated all the groups we need */
1636 if (mali_executor_virtual_group_is_usable()) {
1639 * 2.2. And finally, steal and activate groups
1640 * from virtual group if we need even more
1642 while (0 < num_physical_needed) {
1643 struct mali_group *group;
1645 group = mali_group_acquire_group(virtual_group);
1646 if (NULL != group) {
1647 enum mali_group_state state;
1649 mali_executor_disable_empty_virtual();
1651 state = mali_group_activate(group);
1652 if (MALI_GROUP_STATE_ACTIVE == state) {
1653 /* Group is ready, add to idle list */
1655 &group->executor_list,
1657 group_list_idle_count++;
1658 num_physical_to_process++;
1661 * Group is not ready yet,
1662 * add to inactive list
1665 &group->executor_list,
1666 &group_list_inactive);
1667 group_list_inactive_count++;
1669 trigger_pm_update = MALI_TRUE;
1671 num_physical_needed--;
1674 * We could not get enough groups
1675 * from the virtual group.
1682 /* 2.3. Assign physical jobs to groups */
1684 if (0 < num_physical_to_process) {
1685 struct mali_group *group;
1686 struct mali_group *temp;
1688 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle,
1689 struct mali_group, executor_list) {
1690 struct mali_pp_job *job = NULL;
1691 u32 sub_job = MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS;
1693 MALI_DEBUG_ASSERT(num_jobs_to_start <
1694 MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS);
1696 MALI_DEBUG_ASSERT(0 <
1697 mali_scheduler_job_physical_head_count());
1699 if (mali_executor_hint_is_enabled(
1700 MALI_EXECUTOR_HINT_GP_BOUND)) {
1701 if (MALI_TRUE == mali_executor_tackle_gp_bound()) {
1704 * don't start this right now.
1706 deactivate_idle_group = MALI_FALSE;
1707 num_physical_to_process = 0;
1712 job = mali_scheduler_job_pp_physical_get(
1715 MALI_DEBUG_ASSERT_POINTER(job);
1716 MALI_DEBUG_ASSERT(sub_job <= MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS);
1718 /* Put job + group on list of jobs to start later on */
1720 groups_to_start[num_jobs_to_start] = group;
1721 jobs_to_start[num_jobs_to_start] = job;
1722 sub_jobs_to_start[num_jobs_to_start] = sub_job;
1723 num_jobs_to_start++;
1725 /* Move group from idle to working */
1726 mali_executor_change_state_pp_physical(group,
1728 &group_list_idle_count,
1729 &group_list_working,
1730 &group_list_working_count);
1732 num_physical_to_process--;
1733 if (0 == num_physical_to_process) {
1734 /* Got all we needed */
1742 /* 3. Deactivate idle pp group , must put deactive here before active vitual group
1743 * for cover case first only has physical job in normal queue but group inactive,
1744 * so delay the job start go to active group, when group activated,
1745 * call scheduler again, but now if we get high queue virtual job,
1746 * we will do nothing in schedule cause executor schedule stop
1749 if (MALI_TRUE == mali_executor_deactivate_list_idle(deactivate_idle_group
1750 && (!mali_timeline_has_physical_pp_job()))) {
1751 trigger_pm_update = MALI_TRUE;
1754 /* 4. Activate virtual group, if needed */
1756 if (EXEC_STATE_INACTIVE == virtual_group_state &&
1757 0 < mali_scheduler_job_next_is_virtual()) {
1758 enum mali_group_state state =
1759 mali_group_activate(virtual_group);
1760 if (MALI_GROUP_STATE_ACTIVE == state) {
1761 /* Set virtual group state to idle */
1762 virtual_group_state = EXEC_STATE_IDLE;
1764 trigger_pm_update = MALI_TRUE;
1768 /* 5. To power up group asap, we trigger pm update here. */
1770 if (MALI_TRUE == trigger_pm_update) {
1771 trigger_pm_update = MALI_FALSE;
1772 mali_pm_update_async();
1775 /* 6. Assign jobs to idle virtual group (or deactivate if no job) */
1777 if (EXEC_STATE_IDLE == virtual_group_state) {
1778 if (0 < mali_scheduler_job_next_is_virtual()) {
1779 virtual_job_to_start =
1780 mali_scheduler_job_pp_virtual_get();
1781 virtual_group_state = EXEC_STATE_WORKING;
1782 } else if (!mali_timeline_has_virtual_pp_job()) {
1783 virtual_group_state = EXEC_STATE_INACTIVE;
1785 if (mali_group_deactivate(virtual_group)) {
1786 trigger_pm_update = MALI_TRUE;
1791 /* 7. Assign job to idle GP group (or deactivate if no job) */
1793 if (EXEC_STATE_IDLE == gp_group_state) {
1794 if (0 < mali_scheduler_job_gp_count()) {
1795 gp_job_to_start = mali_scheduler_job_gp_get();
1796 gp_group_state = EXEC_STATE_WORKING;
1797 } else if (!mali_timeline_has_gp_job()) {
1798 gp_group_state = EXEC_STATE_INACTIVE;
1799 if (mali_group_deactivate(gp_group)) {
1800 trigger_pm_update = MALI_TRUE;
1805 /* 8. We no longer need the schedule/queue lock */
1807 mali_scheduler_unlock();
1811 if (NULL != virtual_job_to_start) {
1812 MALI_DEBUG_ASSERT(!mali_group_pp_is_active(virtual_group));
1813 mali_group_start_pp_job(virtual_group,
1814 virtual_job_to_start, 0);
1817 for (i = 0; i < num_jobs_to_start; i++) {
1818 MALI_DEBUG_ASSERT(!mali_group_pp_is_active(
1819 groups_to_start[i]));
1820 mali_group_start_pp_job(groups_to_start[i],
1822 sub_jobs_to_start[i]);
1825 MALI_DEBUG_ASSERT_POINTER(gp_group);
1827 if (NULL != gp_job_to_start) {
1828 MALI_DEBUG_ASSERT(!mali_group_gp_is_active(gp_group));
1829 mali_group_start_gp_job(gp_group, gp_job_to_start);
1832 /* 10. Trigger any pending PM updates */
1833 if (MALI_TRUE == trigger_pm_update) {
1834 mali_pm_update_async();
1838 /* Handler for deferred schedule requests */
1839 static void mali_executor_wq_schedule(void *arg)
1842 mali_executor_lock();
1843 mali_executor_schedule();
1844 mali_executor_unlock();
1847 static void mali_executor_send_gp_oom_to_user(struct mali_gp_job *job, u32 added_size)
1849 _mali_uk_gp_job_suspended_s *jobres;
1850 _mali_osk_notification_t *notification;
1852 notification = mali_gp_job_get_oom_notification(job);
1855 * Remember the id we send to user space, so we have something to
1856 * verify when we get a response
1858 gp_returned_cookie = mali_gp_job_get_id(job);
1860 jobres = (_mali_uk_gp_job_suspended_s *)notification->result_buffer;
1861 jobres->user_job_ptr = mali_gp_job_get_user_id(job);
1862 jobres->cookie = gp_returned_cookie;
1863 jobres->heap_added_size = added_size;
1864 mali_session_send_notification(mali_gp_job_get_session(job),
1867 static struct mali_gp_job *mali_executor_complete_gp(struct mali_group *group,
1870 struct mali_gp_job *job;
1872 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1874 /* Extracts the needed HW status from core and reset */
1875 job = mali_group_complete_gp(group, success);
1877 MALI_DEBUG_ASSERT_POINTER(job);
1879 /* Core is now ready to go into idle list */
1880 gp_group_state = EXEC_STATE_IDLE;
1882 /* This will potentially queue more GP and PP jobs */
1883 mali_timeline_tracker_release(&job->tracker);
1886 mali_gp_job_signal_pp_tracker(job, success);
1891 static struct mali_pp_job *mali_executor_complete_pp(struct mali_group *group,
1894 struct mali_pp_job *job;
1896 mali_bool job_is_done;
1898 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
1900 /* Extracts the needed HW status from core and reset */
1901 job = mali_group_complete_pp(group, success, &sub_job);
1903 MALI_DEBUG_ASSERT_POINTER(job);
1905 /* Core is now ready to go into idle list */
1906 if (mali_group_is_virtual(group)) {
1907 virtual_group_state = EXEC_STATE_IDLE;
1909 /* Move from working to idle state */
1910 mali_executor_change_state_pp_physical(group,
1911 &group_list_working,
1912 &group_list_working_count,
1914 &group_list_idle_count);
1917 /* It is the executor module which owns the jobs themselves by now */
1918 mali_pp_job_mark_sub_job_completed(job, success);
1919 job_is_done = mali_pp_job_is_complete(job);
1922 /* This will potentially queue more GP and PP jobs */
1923 mali_timeline_tracker_release(&job->tracker);
1929 static void mali_executor_complete_group(struct mali_group *group,
1931 struct mali_gp_job **gp_job_done,
1932 struct mali_pp_job **pp_job_done)
1934 struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
1935 struct mali_pp_core *pp_core = mali_group_get_pp_core(group);
1936 struct mali_gp_job *gp_job = NULL;
1937 struct mali_pp_job *pp_job = NULL;
1938 mali_bool pp_job_is_done = MALI_TRUE;
1940 if (NULL != gp_core) {
1941 gp_job = mali_executor_complete_gp(group, success);
1943 MALI_DEBUG_ASSERT_POINTER(pp_core);
1944 MALI_IGNORE(pp_core);
1945 pp_job = mali_executor_complete_pp(group, success);
1947 pp_job_is_done = mali_pp_job_is_complete(pp_job);
1950 if (pause_count > 0) {
1951 /* Execution has been suspended */
1953 if (!mali_executor_is_working()) {
1954 /* Last job completed, wake up sleepers */
1955 _mali_osk_wait_queue_wake_up(
1956 executor_working_wait_queue);
1958 } else if (MALI_TRUE == mali_group_disable_requested(group)) {
1959 mali_executor_core_scale_in_group_complete(group);
1961 mali_executor_schedule();
1963 /* try to schedule new jobs */
1964 mali_executor_schedule();
1967 if (NULL != gp_job) {
1968 MALI_DEBUG_ASSERT_POINTER(gp_job_done);
1969 *gp_job_done = gp_job;
1970 } else if (pp_job_is_done) {
1971 MALI_DEBUG_ASSERT_POINTER(pp_job);
1972 MALI_DEBUG_ASSERT_POINTER(pp_job_done);
1973 *pp_job_done = pp_job;
1977 static void mali_executor_change_state_pp_physical(struct mali_group *group,
1978 _mali_osk_list_t *old_list,
1980 _mali_osk_list_t *new_list,
1984 * It's a bit more complicated to change the state for the physical PP
1985 * groups since their state is determined by the list they are on.
1988 mali_bool found = MALI_FALSE;
1989 struct mali_group *group_iter;
1990 struct mali_group *temp;
1991 u32 old_counted = 0;
1992 u32 new_counted = 0;
1994 MALI_DEBUG_ASSERT_POINTER(group);
1995 MALI_DEBUG_ASSERT_POINTER(old_list);
1996 MALI_DEBUG_ASSERT_POINTER(old_count);
1997 MALI_DEBUG_ASSERT_POINTER(new_list);
1998 MALI_DEBUG_ASSERT_POINTER(new_count);
2001 * Verify that group is present on old list,
2002 * and that the count is correct
2005 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, old_list,
2006 struct mali_group, executor_list) {
2008 if (group == group_iter) {
2013 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, new_list,
2014 struct mali_group, executor_list) {
2018 if (MALI_FALSE == found) {
2019 if (old_list == &group_list_idle) {
2020 MALI_DEBUG_PRINT(1, (" old Group list is idle,"));
2021 } else if (old_list == &group_list_inactive) {
2022 MALI_DEBUG_PRINT(1, (" old Group list is inactive,"));
2023 } else if (old_list == &group_list_working) {
2024 MALI_DEBUG_PRINT(1, (" old Group list is working,"));
2025 } else if (old_list == &group_list_disabled) {
2026 MALI_DEBUG_PRINT(1, (" old Group list is disable,"));
2029 if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_WORKING)) {
2030 MALI_DEBUG_PRINT(1, (" group in working \n"));
2031 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_INACTIVE)) {
2032 MALI_DEBUG_PRINT(1, (" group in inactive \n"));
2033 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_IDLE)) {
2034 MALI_DEBUG_PRINT(1, (" group in idle \n"));
2035 } else if (MALI_TRUE == mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED)) {
2036 MALI_DEBUG_PRINT(1, (" but group in disabled \n"));
2040 MALI_DEBUG_ASSERT(MALI_TRUE == found);
2041 MALI_DEBUG_ASSERT(0 < (*old_count));
2042 MALI_DEBUG_ASSERT((*old_count) == old_counted);
2043 MALI_DEBUG_ASSERT((*new_count) == new_counted);
2046 _mali_osk_list_move(&group->executor_list, new_list);
2051 static void mali_executor_set_state_pp_physical(struct mali_group *group,
2052 _mali_osk_list_t *new_list,
2055 _mali_osk_list_add(&group->executor_list, new_list);
2059 static mali_bool mali_executor_group_is_in_state(struct mali_group *group,
2060 enum mali_executor_state_t state)
2062 MALI_DEBUG_ASSERT_POINTER(group);
2063 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2065 if (gp_group == group) {
2066 if (gp_group_state == state) {
2069 } else if (virtual_group == group || mali_group_is_in_virtual(group)) {
2070 if (virtual_group_state == state) {
2074 /* Physical PP group */
2075 struct mali_group *group_iter;
2076 struct mali_group *temp;
2077 _mali_osk_list_t *list;
2079 if (EXEC_STATE_DISABLED == state) {
2080 list = &group_list_disabled;
2081 } else if (EXEC_STATE_INACTIVE == state) {
2082 list = &group_list_inactive;
2083 } else if (EXEC_STATE_IDLE == state) {
2084 list = &group_list_idle;
2086 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING == state);
2087 list = &group_list_working;
2090 _MALI_OSK_LIST_FOREACHENTRY(group_iter, temp, list,
2091 struct mali_group, executor_list) {
2092 if (group_iter == group) {
2098 /* group not in correct state */
2102 static void mali_executor_group_enable_internal(struct mali_group *group)
2104 MALI_DEBUG_ASSERT(group);
2105 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2106 MALI_DEBUG_ASSERT(mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED));
2108 /* Put into inactive state (== "lowest" enabled state) */
2109 if (group == gp_group) {
2110 MALI_DEBUG_ASSERT(EXEC_STATE_DISABLED == gp_group_state);
2111 gp_group_state = EXEC_STATE_INACTIVE;
2113 mali_executor_change_state_pp_physical(group,
2114 &group_list_disabled,
2115 &group_list_disabled_count,
2116 &group_list_inactive,
2117 &group_list_inactive_count);
2119 ++num_physical_pp_cores_enabled;
2120 MALI_DEBUG_PRINT(4, ("Enabling group id %d \n", group->pp_core->core_id));
2123 if (MALI_GROUP_STATE_ACTIVE == mali_group_activate(group)) {
2124 MALI_DEBUG_ASSERT(MALI_TRUE == mali_group_power_is_on(group));
2126 /* Move from inactive to idle */
2127 if (group == gp_group) {
2128 gp_group_state = EXEC_STATE_IDLE;
2130 mali_executor_change_state_pp_physical(group,
2131 &group_list_inactive,
2132 &group_list_inactive_count,
2134 &group_list_idle_count);
2136 if (mali_executor_has_virtual_group()) {
2137 if (mali_executor_physical_rejoin_virtual(group)) {
2138 mali_pm_update_async();
2143 mali_pm_update_async();
2147 static void mali_executor_group_disable_internal(struct mali_group *group)
2151 MALI_DEBUG_ASSERT_POINTER(group);
2152 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2153 MALI_DEBUG_ASSERT(!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED));
2155 working = mali_executor_group_is_in_state(group, EXEC_STATE_WORKING);
2156 if (MALI_TRUE == working) {
2157 /** Group to be disabled once it completes current work,
2158 * when virtual group completes, also check child groups for this flag */
2159 mali_group_set_disable_request(group, MALI_TRUE);
2163 /* Put into disabled state */
2164 if (group == gp_group) {
2166 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != gp_group_state);
2167 gp_group_state = EXEC_STATE_DISABLED;
2169 if (mali_group_is_in_virtual(group)) {
2170 /* A child group of virtual group. move the specific group from virtual group */
2171 MALI_DEBUG_ASSERT(EXEC_STATE_WORKING != virtual_group_state);
2173 mali_executor_set_state_pp_physical(group,
2174 &group_list_disabled,
2175 &group_list_disabled_count);
2177 mali_group_remove_group(virtual_group, group);
2178 mali_executor_disable_empty_virtual();
2180 mali_executor_change_group_status_disabled(group);
2183 --num_physical_pp_cores_enabled;
2184 MALI_DEBUG_PRINT(4, ("Disabling group id %d \n", group->pp_core->core_id));
2187 if (MALI_GROUP_STATE_INACTIVE != group->state) {
2188 if (MALI_TRUE == mali_group_deactivate(group)) {
2189 mali_pm_update_async();
2194 static void mali_executor_notify_core_change(u32 num_cores)
2196 mali_bool done = MALI_FALSE;
2198 if (mali_is_mali450() || mali_is_mali470()) {
2203 * This function gets a bit complicated because we can't hold the session lock while
2204 * allocating notification objects.
2208 u32 num_sessions_alloc;
2209 u32 num_sessions_with_lock;
2210 u32 used_notification_objects = 0;
2211 _mali_osk_notification_t **notobjs;
2213 /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */
2214 num_sessions_alloc = mali_session_get_count();
2215 if (0 == num_sessions_alloc) {
2216 /* No sessions to report to */
2220 notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc);
2221 if (NULL == notobjs) {
2222 MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n"));
2223 /* there is probably no point in trying again, system must be really low on memory and probably unusable now anyway */
2227 for (i = 0; i < num_sessions_alloc; i++) {
2228 notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_NUM_CORE_CHANGE, sizeof(_mali_uk_pp_num_cores_changed_s));
2229 if (NULL != notobjs[i]) {
2230 _mali_uk_pp_num_cores_changed_s *data = notobjs[i]->result_buffer;
2231 data->number_of_enabled_cores = num_cores;
2233 MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure %u)\n", i));
2237 mali_session_lock();
2239 /* number of sessions will not change while we hold the lock */
2240 num_sessions_with_lock = mali_session_get_count();
2242 if (num_sessions_alloc >= num_sessions_with_lock) {
2243 /* We have allocated enough notification objects for all the sessions atm */
2244 struct mali_session_data *session, *tmp;
2245 MALI_SESSION_FOREACH(session, tmp, link) {
2246 MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc);
2247 if (NULL != notobjs[used_notification_objects]) {
2248 mali_session_send_notification(session, notobjs[used_notification_objects]);
2249 notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */
2251 used_notification_objects++;
2256 mali_session_unlock();
2258 /* Delete any remaining/unused notification objects */
2259 for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) {
2260 if (NULL != notobjs[used_notification_objects]) {
2261 _mali_osk_notification_delete(notobjs[used_notification_objects]);
2265 _mali_osk_free(notobjs);
2269 static mali_bool mali_executor_core_scaling_is_done(void *data)
2273 mali_bool ret = MALI_TRUE;
2277 mali_executor_lock();
2279 num_groups = mali_group_get_glob_num_groups();
2281 for (i = 0; i < num_groups; i++) {
2282 struct mali_group *group = mali_group_get_glob_group(i);
2284 if (NULL != group) {
2285 if (MALI_TRUE == group->disable_requested && NULL != mali_group_get_pp_core(group)) {
2291 mali_executor_unlock();
2296 static void mali_executor_wq_notify_core_change(void *arg)
2300 if (mali_is_mali450() || mali_is_mali470()) {
2304 _mali_osk_wait_queue_wait_event(executor_notify_core_change_wait_queue,
2305 mali_executor_core_scaling_is_done, NULL);
2307 mali_executor_notify_core_change(num_physical_pp_cores_enabled);
2311 * Clear all disable request from the _last_ core scaling behavior.
2313 static void mali_executor_core_scaling_reset(void)
2318 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2320 num_groups = mali_group_get_glob_num_groups();
2322 for (i = 0; i < num_groups; i++) {
2323 struct mali_group *group = mali_group_get_glob_group(i);
2325 if (NULL != group) {
2326 group->disable_requested = MALI_FALSE;
2330 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2331 core_scaling_delay_up_mask[i] = 0;
2335 static void mali_executor_core_scale(unsigned int target_core_nr)
2337 int current_core_scaling_mask[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
2338 int target_core_scaling_mask[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
2341 MALI_DEBUG_ASSERT(0 < target_core_nr);
2342 MALI_DEBUG_ASSERT(num_physical_pp_cores_total >= target_core_nr);
2344 mali_executor_lock();
2346 if (target_core_nr < num_physical_pp_cores_enabled) {
2347 MALI_DEBUG_PRINT(2, ("Requesting %d cores: disabling %d cores\n", target_core_nr, num_physical_pp_cores_enabled - target_core_nr));
2349 MALI_DEBUG_PRINT(2, ("Requesting %d cores: enabling %d cores\n", target_core_nr, target_core_nr - num_physical_pp_cores_enabled));
2352 /* When a new core scaling request is comming, we should remove the un-doing
2353 * part of the last core scaling request. It's safe because we have only one
2354 * lock(executor lock) protection. */
2355 mali_executor_core_scaling_reset();
2357 mali_pm_get_best_power_cost_mask(num_physical_pp_cores_enabled, current_core_scaling_mask);
2358 mali_pm_get_best_power_cost_mask(target_core_nr, target_core_scaling_mask);
2360 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2361 target_core_scaling_mask[i] = target_core_scaling_mask[i] - current_core_scaling_mask[i];
2362 MALI_DEBUG_PRINT(5, ("target_core_scaling_mask[%d] = %d\n", i, target_core_scaling_mask[i]));
2365 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2366 if (0 > target_core_scaling_mask[i]) {
2367 struct mali_pm_domain *domain;
2369 domain = mali_pm_domain_get_from_index(i);
2371 /* Domain is valid and has pp cores */
2372 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2373 struct mali_group *group;
2374 struct mali_group *temp;
2376 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2377 if (NULL != mali_group_get_pp_core(group) && (!mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED))
2378 && (!mali_group_is_virtual(group))) {
2379 mali_executor_group_disable_internal(group);
2380 target_core_scaling_mask[i]++;
2381 if ((0 == target_core_scaling_mask[i])) {
2391 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2393 * Target_core_scaling_mask[i] is bigger than 0,
2394 * means we need to enable some pp cores in
2395 * this domain whose domain index is i.
2397 if (0 < target_core_scaling_mask[i]) {
2398 struct mali_pm_domain *domain;
2400 if (num_physical_pp_cores_enabled >= target_core_nr) {
2404 domain = mali_pm_domain_get_from_index(i);
2406 /* Domain is valid and has pp cores */
2407 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2408 struct mali_group *group;
2409 struct mali_group *temp;
2411 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2412 if (NULL != mali_group_get_pp_core(group) && mali_executor_group_is_in_state(group, EXEC_STATE_DISABLED)
2413 && (!mali_group_is_virtual(group))) {
2414 mali_executor_group_enable_internal(group);
2415 target_core_scaling_mask[i]--;
2417 if ((0 == target_core_scaling_mask[i]) || num_physical_pp_cores_enabled == target_core_nr) {
2427 * Here, we may still have some pp cores not been enabled because of some
2428 * pp cores need to be disabled are still in working state.
2430 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2431 if (0 < target_core_scaling_mask[i]) {
2432 core_scaling_delay_up_mask[i] = target_core_scaling_mask[i];
2436 mali_executor_schedule();
2437 mali_executor_unlock();
2440 static void mali_executor_core_scale_in_group_complete(struct mali_group *group)
2442 int num_pp_cores_disabled = 0;
2443 int num_pp_cores_to_enable = 0;
2446 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2447 MALI_DEBUG_ASSERT(MALI_TRUE == mali_group_disable_requested(group));
2449 /* Disable child group of virtual group */
2450 if (mali_group_is_virtual(group)) {
2451 struct mali_group *child;
2452 struct mali_group *temp;
2454 _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) {
2455 if (MALI_TRUE == mali_group_disable_requested(child)) {
2456 mali_group_set_disable_request(child, MALI_FALSE);
2457 mali_executor_group_disable_internal(child);
2458 num_pp_cores_disabled++;
2461 mali_group_set_disable_request(group, MALI_FALSE);
2463 mali_executor_group_disable_internal(group);
2464 mali_group_set_disable_request(group, MALI_FALSE);
2465 if (NULL != mali_group_get_pp_core(group)) {
2466 num_pp_cores_disabled++;
2470 num_pp_cores_to_enable = num_pp_cores_disabled;
2472 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
2473 if (0 < core_scaling_delay_up_mask[i]) {
2474 struct mali_pm_domain *domain;
2476 if (0 == num_pp_cores_to_enable) {
2480 domain = mali_pm_domain_get_from_index(i);
2482 /* Domain is valid and has pp cores */
2483 if ((NULL != domain) && !(_mali_osk_list_empty(&domain->group_list))) {
2484 struct mali_group *disabled_group;
2485 struct mali_group *temp;
2487 _MALI_OSK_LIST_FOREACHENTRY(disabled_group, temp, &domain->group_list, struct mali_group, pm_domain_list) {
2488 if (NULL != mali_group_get_pp_core(disabled_group) && mali_executor_group_is_in_state(disabled_group, EXEC_STATE_DISABLED)) {
2489 mali_executor_group_enable_internal(disabled_group);
2490 core_scaling_delay_up_mask[i]--;
2491 num_pp_cores_to_enable--;
2493 if ((0 == core_scaling_delay_up_mask[i]) || 0 == num_pp_cores_to_enable) {
2502 _mali_osk_wait_queue_wake_up(executor_notify_core_change_wait_queue);
2505 static void mali_executor_change_group_status_disabled(struct mali_group *group)
2507 /* Physical PP group */
2510 MALI_DEBUG_ASSERT_EXECUTOR_LOCK_HELD();
2512 idle = mali_executor_group_is_in_state(group, EXEC_STATE_IDLE);
2513 if (MALI_TRUE == idle) {
2514 mali_executor_change_state_pp_physical(group,
2516 &group_list_idle_count,
2517 &group_list_disabled,
2518 &group_list_disabled_count);
2520 mali_executor_change_state_pp_physical(group,
2521 &group_list_inactive,
2522 &group_list_inactive_count,
2523 &group_list_disabled,
2524 &group_list_disabled_count);
2528 static mali_bool mali_executor_deactivate_list_idle(mali_bool deactivate_idle_group)
2530 mali_bool trigger_pm_update = MALI_FALSE;
2532 if (group_list_idle_count > 0) {
2533 if (mali_executor_has_virtual_group()) {
2535 /* Rejoin virtual group on Mali-450 */
2537 struct mali_group *group;
2538 struct mali_group *temp;
2540 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
2542 struct mali_group, executor_list) {
2543 if (mali_executor_physical_rejoin_virtual(
2545 trigger_pm_update = MALI_TRUE;
2548 } else if (deactivate_idle_group) {
2549 struct mali_group *group;
2550 struct mali_group *temp;
2552 /* Deactivate group on Mali-300/400 */
2554 _MALI_OSK_LIST_FOREACHENTRY(group, temp,
2556 struct mali_group, executor_list) {
2557 if (mali_group_deactivate(group)) {
2558 trigger_pm_update = MALI_TRUE;
2561 /* Move from idle to inactive */
2562 mali_executor_change_state_pp_physical(group,
2564 &group_list_idle_count,
2565 &group_list_inactive,
2566 &group_list_inactive_count);
2571 return trigger_pm_update;
2574 void mali_executor_running_status_print(void)
2576 struct mali_group *group = NULL;
2577 struct mali_group *temp = NULL;
2579 MALI_PRINT(("GP running job: %p\n", gp_group->gp_running_job));
2580 if ((gp_group->gp_core) && (gp_group->is_working)) {
2581 mali_group_dump_status(gp_group);
2583 MALI_PRINT(("Physical PP groups in WORKING state (count = %u):\n", group_list_working_count));
2584 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, executor_list) {
2585 MALI_PRINT(("PP running job: %p, subjob %d \n", group->pp_running_job, group->pp_running_sub_job));
2586 mali_group_dump_status(group);
2588 MALI_PRINT(("Physical PP groups in INACTIVE state (count = %u):\n", group_list_inactive_count));
2589 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_inactive, struct mali_group, executor_list) {
2590 MALI_PRINT(("\tPP status %d, SW power: %s\n", group->state, group->power_is_on ? "On" : "Off"));
2591 MALI_PRINT(("\tPP #%d: %s\n", group->pp_core->core_id, group->pp_core->hw_core.description));
2593 MALI_PRINT(("Physical PP groups in IDLE state (count = %u):\n", group_list_idle_count));
2594 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, executor_list) {
2595 MALI_PRINT(("\tPP status %d, SW power: %s\n", group->state, group->power_is_on ? "On" : "Off"));
2596 MALI_PRINT(("\tPP #%d: %s\n", group->pp_core->core_id, group->pp_core->hw_core.description));
2598 MALI_PRINT(("Physical PP groups in DISABLED state (count = %u):\n", group_list_disabled_count));
2599 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, executor_list) {
2600 MALI_PRINT(("\tPP status %d, SW power: %s\n", group->state, group->power_is_on ? "On" : "Off"));
2601 MALI_PRINT(("\tPP #%d: %s\n", group->pp_core->core_id, group->pp_core->hw_core.description));
2604 if (mali_executor_has_virtual_group()) {
2605 MALI_PRINT(("Virtual group running job: %p\n", virtual_group->pp_running_job));
2606 MALI_PRINT(("Virtual group status: %d\n", virtual_group_state));
2607 MALI_PRINT(("Virtual group->status: %d\n", virtual_group->state));
2608 MALI_PRINT(("\tSW power: %s\n", virtual_group->power_is_on ? "On" : "Off"));
2609 _MALI_OSK_LIST_FOREACHENTRY(group, temp, &virtual_group->group_list,
2610 struct mali_group, group_list) {
2612 MALI_PRINT(("\tchild group(%s) running job: %p\n", group->pp_core->hw_core.description, group->pp_running_job));
2613 MALI_PRINT(("\tchild group(%s)->status: %d\n", group->pp_core->hw_core.description, group->state));
2614 MALI_PRINT(("\tchild group(%s) SW power: %s\n", group->pp_core->hw_core.description, group->power_is_on ? "On" : "Off"));
2615 if (group->pm_domain) {
2616 MALI_PRINT(("\tPower domain: id %u\n", mali_pm_domain_get_id(group->pm_domain)));
2617 MALI_PRINT(("\tMask:0x%04x \n", mali_pm_domain_get_mask(group->pm_domain)));
2618 MALI_PRINT(("\tUse-count:%u \n", mali_pm_domain_get_use_count(group->pm_domain)));
2619 MALI_PRINT(("\tCurrent power status:%s \n", (mali_pm_domain_get_mask(group->pm_domain)& mali_pm_get_current_mask()) ? "On" : "Off"));
2620 MALI_PRINT(("\tWanted power status:%s \n", (mali_pm_domain_get_mask(group->pm_domain)& mali_pm_get_wanted_mask()) ? "On" : "Off"));
2623 for (i = 0; i < 2; i++) {
2624 if (NULL != group->l2_cache_core[i]) {
2625 struct mali_pm_domain *domain;
2626 domain = mali_l2_cache_get_pm_domain(group->l2_cache_core[i]);
2627 MALI_PRINT(("\t L2(index %d) group SW power: %s\n", i, group->l2_cache_core[i]->power_is_on ? "On" : "Off"));
2629 MALI_PRINT(("\tL2 Power domain: id %u\n", mali_pm_domain_get_id(domain)));
2630 MALI_PRINT(("\tL2 Mask:0x%04x \n", mali_pm_domain_get_mask(domain)));
2631 MALI_PRINT(("\tL2 Use-count:%u \n", mali_pm_domain_get_use_count(domain)));
2632 MALI_PRINT(("\tL2 Current power status:%s \n", (mali_pm_domain_get_mask(domain) & mali_pm_get_current_mask()) ? "On" : "Off"));
2633 MALI_PRINT(("\tL2 Wanted power status:%s \n", (mali_pm_domain_get_mask(domain) & mali_pm_get_wanted_mask()) ? "On" : "Off"));
2638 if (EXEC_STATE_WORKING == virtual_group_state) {
2639 mali_group_dump_status(virtual_group);
2644 void mali_executor_status_dump(void)
2646 mali_executor_lock();
2647 mali_scheduler_lock();
2649 /* print schedule queue status */
2650 mali_scheduler_gp_pp_job_queue_print();
2652 mali_scheduler_unlock();
2653 mali_executor_unlock();