mali_gp_scheduler.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. * This confidential and proprietary software may be used only as
  3. * authorised by a licensing agreement from ARM Limited
  4. * (C) COPYRIGHT 2012-2013 ARM Limited
  5. * ALL RIGHTS RESERVED
  6. * The entire notice above must be reproduced on all authorised
  7. * copies and copies may only be made to the extent permitted
  8. * by a licensing agreement from ARM Limited.
  9. */
  10. #include "mali_gp_scheduler.h"
  11. #include "mali_kernel_common.h"
  12. #include "mali_osk.h"
  13. #include "mali_osk_list.h"
  14. #include "mali_scheduler.h"
  15. #include "mali_gp.h"
  16. #include "mali_gp_job.h"
  17. #include "mali_group.h"
  18. #include "mali_timeline.h"
  19. #include "mali_osk_profiling.h"
  20. #include "mali_kernel_utilization.h"
  21. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  22. #include <linux/sched.h>
  23. #include <trace/events/gpu.h>
  24. #endif
  25. enum mali_gp_slot_state {
  26. MALI_GP_SLOT_STATE_IDLE,
  27. MALI_GP_SLOT_STATE_WORKING,
  28. MALI_GP_SLOT_STATE_DISABLED,
  29. };
  30. /* A render slot is an entity which jobs can be scheduled onto */
  31. struct mali_gp_slot {
  32. struct mali_group *group;
  33. /*
  34. * We keep track of the state here as well as in the group object
  35. * so we don't need to take the group lock so often (and also avoid clutter with the working lock)
  36. */
  37. enum mali_gp_slot_state state;
  38. u32 returned_cookie;
  39. };
  40. static u32 gp_version = 0;
  41. static _MALI_OSK_LIST_HEAD_STATIC_INIT(job_queue); /* List of unscheduled jobs. */
  42. static _MALI_OSK_LIST_HEAD_STATIC_INIT(job_queue_high); /* List of unscheduled high priority jobs. */
  43. static struct mali_gp_slot slot;
  44. /* Variables to allow safe pausing of the scheduler */
  45. static _mali_osk_wait_queue_t *gp_scheduler_working_wait_queue = NULL;
  46. static u32 pause_count = 0;
  47. static mali_bool mali_gp_scheduler_is_suspended(void *data);
  48. static void mali_gp_scheduler_job_queued(void);
  49. static void mali_gp_scheduler_job_completed(void);
  50. #if defined(MALI_UPPER_HALF_SCHEDULING)
  51. static _mali_osk_spinlock_irq_t *gp_scheduler_lock = NULL;
  52. #else
  53. static _mali_osk_spinlock_t *gp_scheduler_lock = NULL;
  54. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  55. _mali_osk_errcode_t mali_gp_scheduler_initialize(void)
  56. {
  57. u32 num_groups;
  58. u32 i;
  59. _mali_osk_errcode_t ret = _MALI_OSK_ERR_OK;
  60. #if defined(MALI_UPPER_HALF_SCHEDULING)
  61. gp_scheduler_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  62. #else
  63. gp_scheduler_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  64. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  65. if (NULL == gp_scheduler_lock) {
  66. ret = _MALI_OSK_ERR_NOMEM;
  67. goto cleanup;
  68. }
  69. gp_scheduler_working_wait_queue = _mali_osk_wait_queue_init();
  70. if (NULL == gp_scheduler_working_wait_queue) {
  71. ret = _MALI_OSK_ERR_NOMEM;
  72. goto cleanup;
  73. }
  74. /* Find all the available GP cores */
  75. num_groups = mali_group_get_glob_num_groups();
  76. for (i = 0; i < num_groups; i++) {
  77. struct mali_group *group = mali_group_get_glob_group(i);
  78. MALI_DEBUG_ASSERT(NULL != group);
  79. if (NULL != group) {
  80. struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
  81. if (NULL != gp_core) {
  82. if (0 == gp_version) {
  83. /* Retrieve GP version */
  84. gp_version = mali_gp_core_get_version(gp_core);
  85. }
  86. slot.group = group;
  87. slot.state = MALI_GP_SLOT_STATE_IDLE;
  88. break; /* There is only one GP, no point in looking for more */
  89. }
  90. } else {
  91. ret = _MALI_OSK_ERR_ITEM_NOT_FOUND;
  92. goto cleanup;
  93. }
  94. }
  95. return _MALI_OSK_ERR_OK;
  96. cleanup:
  97. if (NULL != gp_scheduler_working_wait_queue) {
  98. _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue);
  99. gp_scheduler_working_wait_queue = NULL;
  100. }
  101. if (NULL != gp_scheduler_lock) {
  102. #if defined(MALI_UPPER_HALF_SCHEDULING)
  103. _mali_osk_spinlock_irq_term(gp_scheduler_lock);
  104. #else
  105. _mali_osk_spinlock_term(gp_scheduler_lock);
  106. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  107. gp_scheduler_lock = NULL;
  108. }
  109. return ret;
  110. }
  111. void mali_gp_scheduler_terminate(void)
  112. {
  113. MALI_DEBUG_ASSERT( MALI_GP_SLOT_STATE_IDLE == slot.state
  114. || MALI_GP_SLOT_STATE_DISABLED == slot.state);
  115. MALI_DEBUG_ASSERT_POINTER(slot.group);
  116. mali_group_delete(slot.group);
  117. _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue);
  118. #if defined(MALI_UPPER_HALF_SCHEDULING)
  119. _mali_osk_spinlock_irq_term(gp_scheduler_lock);
  120. #else
  121. _mali_osk_spinlock_term(gp_scheduler_lock);
  122. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  123. }
  124. MALI_STATIC_INLINE void mali_gp_scheduler_lock(void)
  125. {
  126. #if defined(MALI_UPPER_HALF_SCHEDULING)
  127. _mali_osk_spinlock_irq_lock(gp_scheduler_lock);
  128. #else
  129. _mali_osk_spinlock_lock(gp_scheduler_lock);
  130. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  131. MALI_DEBUG_PRINT(5, ("Mali GP scheduler: GP scheduler lock taken\n"));
  132. }
  133. MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void)
  134. {
  135. MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n"));
  136. #if defined(MALI_UPPER_HALF_SCHEDULING)
  137. _mali_osk_spinlock_irq_unlock(gp_scheduler_lock);
  138. #else
  139. _mali_osk_spinlock_unlock(gp_scheduler_lock);
  140. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  141. }
  142. #if defined(DEBUG)
  143. #define MALI_ASSERT_GP_SCHEDULER_LOCKED() MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock)
  144. #else
  145. #define MALI_ASSERT_GP_SCHEDULER_LOCKED() do {} while (0)
  146. #endif /* defined(DEBUG) */
  147. /* Group and scheduler must be locked when entering this function. Both will be unlocked before
  148. * exiting. */
  149. static void mali_gp_scheduler_schedule_internal_and_unlock(void)
  150. {
  151. struct mali_gp_job *job = NULL;
  152. MALI_DEBUG_ASSERT_LOCK_HELD(slot.group->lock);
  153. MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock);
  154. if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state ||
  155. (_mali_osk_list_empty(&job_queue) && _mali_osk_list_empty(&job_queue_high))) {
  156. mali_gp_scheduler_unlock();
  157. mali_group_unlock(slot.group);
  158. MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n",
  159. pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0));
  160. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  161. trace_gpu_sched_switch(mali_gp_get_hw_core_desc(group->gp_core), sched_clock(), 0, 0, 0);
  162. #endif
  163. return; /* Nothing to do, so early out */
  164. }
  165. /* Get next job in queue */
  166. if (!_mali_osk_list_empty(&job_queue_high)) {
  167. job = _MALI_OSK_LIST_ENTRY(job_queue_high.next, struct mali_gp_job, list);
  168. } else {
  169. MALI_DEBUG_ASSERT(!_mali_osk_list_empty(&job_queue));
  170. job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_gp_job, list);
  171. }
  172. MALI_DEBUG_ASSERT_POINTER(job);
  173. /* Remove the job from queue */
  174. _mali_osk_list_del(&job->list);
  175. /* Mark slot as busy */
  176. slot.state = MALI_GP_SLOT_STATE_WORKING;
  177. mali_gp_scheduler_unlock();
  178. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Starting job %u (0x%08X)\n", mali_gp_job_get_id(job), job));
  179. mali_group_start_gp_job(slot.group, job);
  180. mali_group_unlock(slot.group);
  181. }
  182. void mali_gp_scheduler_schedule(void)
  183. {
  184. mali_group_lock(slot.group);
  185. mali_gp_scheduler_lock();
  186. mali_gp_scheduler_schedule_internal_and_unlock();
  187. }
  188. static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success)
  189. {
  190. _mali_uk_gp_job_finished_s *jobres = job->finished_notification->result_buffer;
  191. _mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
  192. jobres->user_job_ptr = mali_gp_job_get_user_id(job);
  193. if (MALI_TRUE == success) {
  194. jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
  195. } else {
  196. jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
  197. }
  198. jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job);
  199. jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job);
  200. jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job);
  201. mali_session_send_notification(mali_gp_job_get_session(job), job->finished_notification);
  202. job->finished_notification = NULL;
  203. mali_gp_job_delete(job);
  204. mali_gp_scheduler_job_completed();
  205. }
  206. /* Group must be locked when entering this function. Will be unlocked before exiting. */
  207. void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success)
  208. {
  209. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  210. MALI_DEBUG_ASSERT_POINTER(group);
  211. MALI_DEBUG_ASSERT_POINTER(job);
  212. MALI_DEBUG_ASSERT_LOCK_HELD(group->lock);
  213. MALI_DEBUG_ASSERT(slot.group == group);
  214. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) completed (%s)\n", mali_gp_job_get_id(job), job, success ? "success" : "failure"));
  215. /* Release tracker. */
  216. schedule_mask |= mali_timeline_tracker_release(&job->tracker);
  217. /* Signal PP job. */
  218. schedule_mask |= mali_gp_job_signal_pp_tracker(job, success);
  219. mali_gp_scheduler_lock();
  220. /* Mark slot as idle again */
  221. slot.state = MALI_GP_SLOT_STATE_IDLE;
  222. /* If paused, then this was the last job, so wake up sleeping workers */
  223. if (pause_count > 0) {
  224. _mali_osk_wait_queue_wake_up(gp_scheduler_working_wait_queue);
  225. }
  226. /* Schedule any queued GP jobs on this group. */
  227. mali_gp_scheduler_schedule_internal_and_unlock();
  228. /* GP is now scheduled, removing it from the mask. */
  229. schedule_mask &= ~MALI_SCHEDULER_MASK_GP;
  230. if (MALI_SCHEDULER_MASK_EMPTY != schedule_mask) {
  231. /* Releasing the tracker activated other jobs that need scheduling. */
  232. mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
  233. }
  234. /* Sends the job end message to user space and free the job object */
  235. mali_gp_scheduler_return_job_to_user(job, success);
  236. }
  237. void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job)
  238. {
  239. _mali_uk_gp_job_suspended_s * jobres;
  240. _mali_osk_notification_t * notification;
  241. mali_gp_scheduler_lock();
  242. notification = job->oom_notification;
  243. job->oom_notification = NULL;
  244. slot.returned_cookie = mali_gp_job_get_id(job);
  245. jobres = (_mali_uk_gp_job_suspended_s *)notification->result_buffer;
  246. jobres->user_job_ptr = mali_gp_job_get_user_id(job);
  247. jobres->cookie = mali_gp_job_get_id(job);
  248. mali_gp_scheduler_unlock();
  249. mali_session_send_notification(mali_gp_job_get_session(job), notification);
  250. /*
  251. * If this function failed, then we could return the job to user space right away,
  252. * but there is a job timer anyway that will do that eventually.
  253. * This is not exactly a common case anyway.
  254. */
  255. }
  256. void mali_gp_scheduler_suspend(void)
  257. {
  258. mali_gp_scheduler_lock();
  259. pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */
  260. mali_gp_scheduler_unlock();
  261. _mali_osk_wait_queue_wait_event(gp_scheduler_working_wait_queue, mali_gp_scheduler_is_suspended, NULL);
  262. }
  263. void mali_gp_scheduler_resume(void)
  264. {
  265. mali_gp_scheduler_lock();
  266. pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */
  267. mali_gp_scheduler_unlock();
  268. if (0 == pause_count) {
  269. mali_gp_scheduler_schedule();
  270. }
  271. }
  272. mali_timeline_point mali_gp_scheduler_submit_job(struct mali_session_data *session, struct mali_gp_job *job)
  273. {
  274. mali_timeline_point point;
  275. MALI_DEBUG_ASSERT_POINTER(session);
  276. MALI_DEBUG_ASSERT_POINTER(job);
  277. mali_gp_scheduler_job_queued();
  278. /* Add job to Timeline system. */
  279. point = mali_timeline_system_add_tracker(session->timeline_system, &job->tracker, MALI_TIMELINE_GP);
  280. return point;
  281. }
  282. _mali_osk_errcode_t _mali_ukk_gp_start_job(void *ctx, _mali_uk_gp_start_job_s *uargs)
  283. {
  284. struct mali_session_data *session;
  285. struct mali_gp_job *job;
  286. mali_timeline_point point;
  287. u32 __user *timeline_point_ptr = NULL;
  288. MALI_DEBUG_ASSERT_POINTER(uargs);
  289. MALI_DEBUG_ASSERT_POINTER(ctx);
  290. session = (struct mali_session_data*)ctx;
  291. job = mali_gp_job_create(session, uargs, mali_scheduler_get_new_id(), NULL);
  292. if (NULL == job) {
  293. MALI_PRINT_ERROR(("Failed to create GP job.\n"));
  294. return _MALI_OSK_ERR_NOMEM;
  295. }
  296. timeline_point_ptr = (u32 __user *) job->uargs.timeline_point_ptr;
  297. point = mali_gp_scheduler_submit_job(session, job);
  298. if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) {
  299. /* Let user space know that something failed after the job was started. */
  300. return _MALI_OSK_ERR_ITEM_NOT_FOUND;
  301. }
  302. return _MALI_OSK_ERR_OK;
  303. }
  304. _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args)
  305. {
  306. MALI_DEBUG_ASSERT_POINTER(args);
  307. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  308. args->number_of_cores = 1;
  309. return _MALI_OSK_ERR_OK;
  310. }
  311. _mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args)
  312. {
  313. MALI_DEBUG_ASSERT_POINTER(args);
  314. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  315. args->version = gp_version;
  316. return _MALI_OSK_ERR_OK;
  317. }
  318. _mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args)
  319. {
  320. struct mali_session_data *session;
  321. struct mali_gp_job *resumed_job;
  322. _mali_osk_notification_t *new_notification = 0;
  323. MALI_DEBUG_ASSERT_POINTER(args);
  324. if (NULL == args->ctx) {
  325. return _MALI_OSK_ERR_INVALID_ARGS;
  326. }
  327. session = (struct mali_session_data*)args->ctx;
  328. if (NULL == session) {
  329. return _MALI_OSK_ERR_FAULT;
  330. }
  331. if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) {
  332. new_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));
  333. if (NULL == new_notification) {
  334. MALI_PRINT_ERROR(("Mali GP scheduler: Failed to allocate notification object. Will abort GP job.\n"));
  335. mali_group_lock(slot.group);
  336. mali_group_abort_gp_job(slot.group, args->cookie);
  337. mali_group_unlock(slot.group);
  338. return _MALI_OSK_ERR_FAULT;
  339. }
  340. }
  341. mali_group_lock(slot.group);
  342. if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) {
  343. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1]));
  344. resumed_job = mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]);
  345. if (NULL != resumed_job) {
  346. resumed_job->oom_notification = new_notification;
  347. mali_group_unlock(slot.group);
  348. return _MALI_OSK_ERR_OK;
  349. } else {
  350. mali_group_unlock(slot.group);
  351. _mali_osk_notification_delete(new_notification);
  352. return _MALI_OSK_ERR_FAULT;
  353. }
  354. }
  355. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie));
  356. mali_group_abort_gp_job(slot.group, args->cookie);
  357. mali_group_unlock(slot.group);
  358. return _MALI_OSK_ERR_OK;
  359. }
  360. void mali_gp_scheduler_abort_session(struct mali_session_data *session)
  361. {
  362. struct mali_gp_job *job, *tmp;
  363. _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs);
  364. MALI_DEBUG_ASSERT_POINTER(session);
  365. MALI_DEBUG_ASSERT(session->is_aborting);
  366. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting all jobs from session 0x%08X.\n", session));
  367. mali_gp_scheduler_lock();
  368. /* Find all jobs from the aborting session. */
  369. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_gp_job, list) {
  370. if (job->session == session) {
  371. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Removing job %u (0x%08X) from queue.\n", mali_gp_job_get_id(job), job));
  372. _mali_osk_list_move(&job->list, &removed_jobs);
  373. }
  374. }
  375. /* Find all high priority jobs from the aborting session. */
  376. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue_high, struct mali_gp_job, list) {
  377. if (job->session == session) {
  378. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Removing job %u (0x%08X) from queue.\n", mali_gp_job_get_id(job), job));
  379. _mali_osk_list_move(&job->list, &removed_jobs);
  380. }
  381. }
  382. mali_gp_scheduler_unlock();
  383. /* Release and delete all found jobs from the aborting session. */
  384. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &removed_jobs, struct mali_gp_job, list) {
  385. mali_timeline_tracker_release(&job->tracker);
  386. mali_gp_job_signal_pp_tracker(job, MALI_FALSE);
  387. mali_gp_job_delete(job);
  388. mali_gp_scheduler_job_completed();
  389. }
  390. /* Abort any running jobs from the session. */
  391. mali_group_abort_session(slot.group, session);
  392. }
  393. static mali_bool mali_gp_scheduler_is_suspended(void *data)
  394. {
  395. mali_bool ret;
  396. /* This callback does not use the data pointer. */
  397. MALI_IGNORE(data);
  398. mali_gp_scheduler_lock();
  399. ret = pause_count > 0 && (slot.state == MALI_GP_SLOT_STATE_IDLE || slot.state == MALI_GP_SLOT_STATE_DISABLED);
  400. mali_gp_scheduler_unlock();
  401. return ret;
  402. }
  403. #if MALI_STATE_TRACKING
  404. u32 mali_gp_scheduler_dump_state(char *buf, u32 size)
  405. {
  406. int n = 0;
  407. n += _mali_osk_snprintf(buf + n, size - n, "GP\n");
  408. n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty");
  409. n += _mali_osk_snprintf(buf + n, size - n, "\tHigh priority queue is %s\n", _mali_osk_list_empty(&job_queue_high) ? "empty" : "not empty");
  410. n += mali_group_dump_state(slot.group, buf + n, size - n);
  411. n += _mali_osk_snprintf(buf + n, size - n, "\n");
  412. return n;
  413. }
  414. #endif
  415. void mali_gp_scheduler_reset_all_groups(void)
  416. {
  417. if (NULL != slot.group) {
  418. mali_group_lock(slot.group);
  419. mali_group_reset(slot.group);
  420. mali_group_unlock(slot.group);
  421. }
  422. }
  423. void mali_gp_scheduler_zap_all_active(struct mali_session_data *session)
  424. {
  425. if (NULL != slot.group) {
  426. mali_group_zap_session(slot.group, session);
  427. }
  428. }
  429. void mali_gp_scheduler_enable_group(struct mali_group *group)
  430. {
  431. MALI_DEBUG_ASSERT_POINTER(group);
  432. MALI_DEBUG_ASSERT(slot.group == group);
  433. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: enabling gp group %p\n", group));
  434. mali_group_lock(group);
  435. if (MALI_GROUP_STATE_DISABLED != group->state) {
  436. mali_group_unlock(group);
  437. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: gp group %p already enabled\n", group));
  438. return;
  439. }
  440. mali_gp_scheduler_lock();
  441. MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state);
  442. MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_DISABLED == slot.state);
  443. slot.state = MALI_GP_SLOT_STATE_IDLE;
  444. group->state = MALI_GROUP_STATE_IDLE;
  445. mali_group_power_on_group(group);
  446. mali_group_reset(group);
  447. /* Pick up any jobs that might have been queued while the GP group was disabled. */
  448. mali_gp_scheduler_schedule_internal_and_unlock();
  449. }
  450. void mali_gp_scheduler_disable_group(struct mali_group *group)
  451. {
  452. MALI_DEBUG_ASSERT_POINTER(group);
  453. MALI_DEBUG_ASSERT(slot.group == group);
  454. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: disabling gp group %p\n", group));
  455. mali_gp_scheduler_suspend();
  456. mali_group_lock(group);
  457. mali_gp_scheduler_lock();
  458. MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state
  459. || MALI_GROUP_STATE_DISABLED == group->state);
  460. if (MALI_GROUP_STATE_DISABLED == group->state) {
  461. MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_DISABLED == slot.state);
  462. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: gp group %p already disabled\n", group));
  463. } else {
  464. MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_IDLE == slot.state);
  465. slot.state = MALI_GP_SLOT_STATE_DISABLED;
  466. group->state = MALI_GROUP_STATE_DISABLED;
  467. mali_group_power_off_group(group, MALI_TRUE);
  468. }
  469. mali_gp_scheduler_unlock();
  470. mali_group_unlock(group);
  471. mali_gp_scheduler_resume();
  472. }
  473. static mali_scheduler_mask mali_gp_scheduler_queue_job(struct mali_gp_job *job)
  474. {
  475. _mali_osk_list_t *queue = NULL;
  476. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  477. struct mali_gp_job *iter, *tmp;
  478. MALI_DEBUG_ASSERT_POINTER(job);
  479. MALI_DEBUG_ASSERT_POINTER(job->session);
  480. MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock);
  481. _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GP_ENQUEUE, job->pid, job->tid, job->uargs.frame_builder_id, job->uargs.flush_id, 0);
  482. job->cache_order = mali_scheduler_get_new_cache_order();
  483. /* Determine which queue the job should be added to. */
  484. if (job->session->use_high_priority_job_queue) {
  485. queue = &job_queue_high;
  486. } else {
  487. queue = &job_queue;
  488. }
  489. /* Find position in queue where job should be added. */
  490. _MALI_OSK_LIST_FOREACHENTRY_REVERSE(iter, tmp, queue, struct mali_gp_job, list) {
  491. if (mali_gp_job_is_after(job, iter)) {
  492. break;
  493. }
  494. }
  495. /* Add job to queue. */
  496. _mali_osk_list_add(&job->list, &iter->list);
  497. /* Set schedule bitmask if the GP core is idle. */
  498. if (MALI_GP_SLOT_STATE_IDLE == slot.state) {
  499. schedule_mask |= MALI_SCHEDULER_MASK_GP;
  500. }
  501. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  502. trace_gpu_job_enqueue(mali_gp_job_get_tid(job), mali_gp_job_get_id(job), "GP");
  503. #endif
  504. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n", mali_gp_job_get_id(job), job));
  505. return schedule_mask;
  506. }
  507. mali_scheduler_mask mali_gp_scheduler_activate_job(struct mali_gp_job *job)
  508. {
  509. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  510. MALI_DEBUG_ASSERT_POINTER(job);
  511. MALI_DEBUG_ASSERT_POINTER(job->session);
  512. MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Timeline activation for job %u (0x%08X).\n", mali_gp_job_get_id(job), job));
  513. mali_gp_scheduler_lock();
  514. if (unlikely(job->session->is_aborting)) {
  515. /* Before checking if the session is aborting, the scheduler must be locked. */
  516. MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock);
  517. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) activated while session is aborting.\n", mali_gp_job_get_id(job), job));
  518. /* This job should not be on any list. */
  519. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
  520. mali_gp_scheduler_unlock();
  521. /* Release tracker and delete job. */
  522. mali_timeline_tracker_release(&job->tracker);
  523. mali_gp_job_signal_pp_tracker(job, MALI_FALSE);
  524. mali_gp_job_delete(job);
  525. mali_gp_scheduler_job_completed();
  526. /* Since we are aborting we ignore the scheduler mask. */
  527. return MALI_SCHEDULER_MASK_EMPTY;
  528. }
  529. /* GP job is ready to run, queue it. */
  530. schedule_mask = mali_gp_scheduler_queue_job(job);
  531. mali_gp_scheduler_unlock();
  532. return schedule_mask;
  533. }
  534. static void mali_gp_scheduler_job_queued(void)
  535. {
  536. /* We hold a PM reference for every job we hold queued (and running) */
  537. _mali_osk_pm_dev_ref_add();
  538. if (mali_utilization_enabled()) {
  539. /*
  540. * We cheat a little bit by counting the PP as busy from the time a GP job is queued.
  541. * This will be fine because we only loose the tiny idle gap between jobs, but
  542. * we will instead get less utilization work to do (less locks taken)
  543. */
  544. mali_utilization_gp_start();
  545. }
  546. }
  547. static void mali_gp_scheduler_job_completed(void)
  548. {
  549. /* Release the PM reference we got in the mali_gp_scheduler_job_queued() function */
  550. _mali_osk_pm_dev_ref_dec();
  551. if (mali_utilization_enabled()) {
  552. mali_utilization_gp_end();
  553. }
  554. }