mali_pp_scheduler.c 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067
  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_pp_scheduler.h"
  11. #include "mali_kernel_common.h"
  12. #include "mali_kernel_core.h"
  13. #include "mali_osk.h"
  14. #include "mali_osk_list.h"
  15. #include "mali_scheduler.h"
  16. #include "mali_pp.h"
  17. #include "mali_pp_job.h"
  18. #include "mali_group.h"
  19. #include "mali_pm.h"
  20. #include "mali_timeline.h"
  21. #include "mali_osk_profiling.h"
  22. #include "mali_kernel_utilization.h"
  23. #include "mali_session.h"
  24. #include "mali_pm_domain.h"
  25. #include "linux/mali/mali_utgard.h"
  26. #if defined(CONFIG_DMA_SHARED_BUFFER)
  27. #include "mali_memory_dma_buf.h"
  28. #endif
  29. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  30. #include <linux/sched.h>
  31. #include <trace/events/gpu.h>
  32. #endif
  33. /* Queue type used for physical and virtual job queues. */
  34. struct mali_pp_scheduler_job_queue {
  35. _MALI_OSK_LIST_HEAD(normal_pri); /* List of jobs with some unscheduled work. */
  36. _MALI_OSK_LIST_HEAD(high_pri); /* List of high priority jobs with some unscheduled work. */
  37. u32 depth; /* Depth of combined queues. */
  38. };
  39. /* If dma_buf with map on demand is used, we defer job deletion and job queue if in atomic context,
  40. * since both might sleep. */
  41. #if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
  42. #define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE 1
  43. #define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE 1
  44. #endif /* !defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) */
  45. static void mali_pp_scheduler_job_queued(void);
  46. static void mali_pp_scheduler_job_completed(void);
  47. /* Maximum of 8 PP cores (a group can only have maximum of 1 PP core) */
  48. #define MALI_MAX_NUMBER_OF_PP_GROUPS 9
  49. static mali_bool mali_pp_scheduler_is_suspended(void *data);
  50. static u32 pp_version = 0;
  51. /* Physical job queue */
  52. static struct mali_pp_scheduler_job_queue job_queue;
  53. /* Physical groups */
  54. static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_working); /* List of physical groups with working jobs on the pp core */
  55. static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_idle); /* List of physical groups with idle jobs on the pp core */
  56. static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_disabled); /* List of disabled physical groups */
  57. /* Virtual job queue (Mali-450 only) */
  58. static struct mali_pp_scheduler_job_queue virtual_job_queue;
  59. /**
  60. * Add job to scheduler queue.
  61. *
  62. * @param job Job to queue.
  63. * @return Schedule mask.
  64. */
  65. static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job);
  66. /* Virtual group (Mali-450 only) */
  67. static struct mali_group *virtual_group = NULL; /* Virtual group (if any) */
  68. static enum {
  69. VIRTUAL_GROUP_IDLE,
  70. VIRTUAL_GROUP_WORKING,
  71. VIRTUAL_GROUP_DISABLED,
  72. }
  73. virtual_group_state = VIRTUAL_GROUP_IDLE; /* Flag which indicates whether the virtual group is working or idle */
  74. /* Number of physical cores */
  75. static u32 num_cores = 0;
  76. /* Number of physical cores which are enabled */
  77. static u32 enabled_cores = 0;
  78. /* Enable or disable core scaling */
  79. static mali_bool core_scaling_enabled = MALI_TRUE;
  80. /* Variables to allow safe pausing of the scheduler */
  81. static _mali_osk_wait_queue_t *pp_scheduler_working_wait_queue = NULL;
  82. static u32 pause_count = 0;
  83. #if defined(MALI_UPPER_HALF_SCHEDULING)
  84. static _mali_osk_spinlock_irq_t *pp_scheduler_lock = NULL;
  85. #else
  86. static _mali_osk_spinlock_t *pp_scheduler_lock = NULL;
  87. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  88. MALI_STATIC_INLINE void mali_pp_scheduler_lock(void)
  89. {
  90. #if defined(MALI_UPPER_HALF_SCHEDULING)
  91. _mali_osk_spinlock_irq_lock(pp_scheduler_lock);
  92. #else
  93. _mali_osk_spinlock_lock(pp_scheduler_lock);
  94. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  95. MALI_DEBUG_PRINT(5, ("Mali PP scheduler: PP scheduler lock taken.\n"));
  96. }
  97. MALI_STATIC_INLINE void mali_pp_scheduler_unlock(void)
  98. {
  99. MALI_DEBUG_PRINT(5, ("Mali PP scheduler: Releasing PP scheduler lock.\n"));
  100. #if defined(MALI_UPPER_HALF_SCHEDULING)
  101. _mali_osk_spinlock_irq_unlock(pp_scheduler_lock);
  102. #else
  103. _mali_osk_spinlock_unlock(pp_scheduler_lock);
  104. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  105. }
  106. #if defined(DEBUG)
  107. #define MALI_ASSERT_PP_SCHEDULER_LOCKED() MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock)
  108. #else
  109. #define MALI_ASSERT_PP_SCHEDULER_LOCKED() do {} while (0)
  110. #endif /* defined(DEBUG) */
  111. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  112. static _mali_osk_wq_work_t *pp_scheduler_wq_job_delete = NULL;
  113. static _mali_osk_spinlock_irq_t *pp_scheduler_job_delete_lock = NULL;
  114. static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_deletion_queue);
  115. static void mali_pp_scheduler_deferred_job_delete(struct mali_pp_job *job)
  116. {
  117. MALI_DEBUG_ASSERT_POINTER(job);
  118. _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock);
  119. /* This job object should not be on any lists. */
  120. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
  121. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
  122. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
  123. _mali_osk_list_addtail(&job->list, &pp_scheduler_job_deletion_queue);
  124. _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock);
  125. _mali_osk_wq_schedule_work(pp_scheduler_wq_job_delete);
  126. }
  127. static void mali_pp_scheduler_do_job_delete(void *arg)
  128. {
  129. _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
  130. struct mali_pp_job *job;
  131. struct mali_pp_job *tmp;
  132. MALI_IGNORE(arg);
  133. _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock);
  134. /*
  135. * Quickly "unhook" the jobs pending to be deleted, so we can release the lock before
  136. * we start deleting the job objects (without any locks held
  137. */
  138. _mali_osk_list_move_list(&pp_scheduler_job_deletion_queue, &list);
  139. _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock);
  140. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) {
  141. mali_pp_job_delete(job); /* delete the job object itself */
  142. }
  143. }
  144. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
  145. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  146. static _mali_osk_wq_work_t *pp_scheduler_wq_job_queue = NULL;
  147. static _mali_osk_spinlock_irq_t *pp_scheduler_job_queue_lock = NULL;
  148. static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_queue_list);
  149. static void mali_pp_scheduler_deferred_job_queue(struct mali_pp_job *job)
  150. {
  151. MALI_DEBUG_ASSERT_POINTER(job);
  152. _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock);
  153. _mali_osk_list_addtail(&job->list, &pp_scheduler_job_queue_list);
  154. _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock);
  155. _mali_osk_wq_schedule_work(pp_scheduler_wq_job_queue);
  156. }
  157. static void mali_pp_scheduler_do_job_queue(void *arg)
  158. {
  159. _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
  160. struct mali_pp_job *job;
  161. struct mali_pp_job *tmp;
  162. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  163. MALI_IGNORE(arg);
  164. _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock);
  165. /*
  166. * Quickly "unhook" the jobs pending to be queued, so we can release the lock before
  167. * we start queueing the job objects (without any locks held)
  168. */
  169. _mali_osk_list_move_list(&pp_scheduler_job_queue_list, &list);
  170. _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock);
  171. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) {
  172. _mali_osk_list_delinit(&job->list);
  173. schedule_mask |= mali_pp_scheduler_queue_job(job);
  174. }
  175. mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
  176. }
  177. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  178. MALI_STATIC_INLINE mali_bool mali_pp_scheduler_has_virtual_group(void)
  179. {
  180. #if (defined(CONFIG_MALI450) || defined(CONFIG_MALI470))
  181. return NULL != virtual_group;
  182. #else
  183. return MALI_FALSE;
  184. #endif /* defined(CONFIG_MALI450) || defined(CONFIG_MALI470) */
  185. }
  186. _mali_osk_errcode_t mali_pp_scheduler_initialize(void)
  187. {
  188. _MALI_OSK_INIT_LIST_HEAD(&job_queue.normal_pri);
  189. _MALI_OSK_INIT_LIST_HEAD(&job_queue.high_pri);
  190. job_queue.depth = 0;
  191. _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.normal_pri);
  192. _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.high_pri);
  193. virtual_job_queue.depth = 0;
  194. #if defined(MALI_UPPER_HALF_SCHEDULING)
  195. pp_scheduler_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  196. #else
  197. pp_scheduler_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  198. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  199. if (NULL == pp_scheduler_lock) goto cleanup;
  200. pp_scheduler_working_wait_queue = _mali_osk_wait_queue_init();
  201. if (NULL == pp_scheduler_working_wait_queue) goto cleanup;
  202. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  203. pp_scheduler_wq_job_delete = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_delete, NULL);
  204. if (NULL == pp_scheduler_wq_job_delete) goto cleanup;
  205. pp_scheduler_job_delete_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
  206. if (NULL == pp_scheduler_job_delete_lock) goto cleanup;
  207. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
  208. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  209. pp_scheduler_wq_job_queue = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_queue, NULL);
  210. if (NULL == pp_scheduler_wq_job_queue) goto cleanup;
  211. pp_scheduler_job_queue_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
  212. if (NULL == pp_scheduler_job_queue_lock) goto cleanup;
  213. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  214. return _MALI_OSK_ERR_OK;
  215. cleanup:
  216. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  217. if (NULL != pp_scheduler_job_queue_lock) {
  218. _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock);
  219. pp_scheduler_job_queue_lock = NULL;
  220. }
  221. if (NULL != pp_scheduler_wq_job_queue) {
  222. _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue);
  223. pp_scheduler_wq_job_queue = NULL;
  224. }
  225. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  226. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  227. if (NULL != pp_scheduler_job_delete_lock) {
  228. _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock);
  229. pp_scheduler_job_delete_lock = NULL;
  230. }
  231. if (NULL != pp_scheduler_wq_job_delete) {
  232. _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete);
  233. pp_scheduler_wq_job_delete = NULL;
  234. }
  235. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
  236. if (NULL != pp_scheduler_working_wait_queue) {
  237. _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue);
  238. pp_scheduler_working_wait_queue = NULL;
  239. }
  240. if (NULL != pp_scheduler_lock) {
  241. #if defined(MALI_UPPER_HALF_SCHEDULING)
  242. _mali_osk_spinlock_irq_term(pp_scheduler_lock);
  243. #else
  244. _mali_osk_spinlock_term(pp_scheduler_lock);
  245. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  246. pp_scheduler_lock = NULL;
  247. }
  248. return _MALI_OSK_ERR_NOMEM;
  249. }
  250. void mali_pp_scheduler_terminate(void)
  251. {
  252. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  253. _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock);
  254. _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue);
  255. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  256. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  257. _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock);
  258. _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete);
  259. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
  260. _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue);
  261. #if defined(MALI_UPPER_HALF_SCHEDULING)
  262. _mali_osk_spinlock_irq_term(pp_scheduler_lock);
  263. #else
  264. _mali_osk_spinlock_term(pp_scheduler_lock);
  265. #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
  266. }
  267. void mali_pp_scheduler_populate(void)
  268. {
  269. struct mali_group *group;
  270. struct mali_pp_core *pp_core;
  271. u32 num_groups;
  272. u32 i;
  273. num_groups = mali_group_get_glob_num_groups();
  274. /* Do we have a virtual group? */
  275. for (i = 0; i < num_groups; i++) {
  276. group = mali_group_get_glob_group(i);
  277. if (mali_group_is_virtual(group)) {
  278. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Found virtual group %p.\n", group));
  279. virtual_group = group;
  280. break;
  281. }
  282. }
  283. /* Find all the available PP cores */
  284. for (i = 0; i < num_groups; i++) {
  285. group = mali_group_get_glob_group(i);
  286. pp_core = mali_group_get_pp_core(group);
  287. if (NULL != pp_core && !mali_group_is_virtual(group)) {
  288. if (0 == pp_version) {
  289. /* Retrieve PP version from the first available PP core */
  290. pp_version = mali_pp_core_get_version(pp_core);
  291. }
  292. if (mali_pp_scheduler_has_virtual_group()) {
  293. /* Add all physical PP cores to the virtual group */
  294. mali_group_lock(virtual_group);
  295. group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
  296. mali_group_add_group(virtual_group, group, MALI_TRUE);
  297. mali_group_unlock(virtual_group);
  298. } else {
  299. _mali_osk_list_add(&group->pp_scheduler_list, &group_list_idle);
  300. }
  301. num_cores++;
  302. }
  303. }
  304. enabled_cores = num_cores;
  305. }
  306. void mali_pp_scheduler_depopulate(void)
  307. {
  308. struct mali_group *group, *temp;
  309. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
  310. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
  311. /* Delete all groups owned by scheduler */
  312. if (mali_pp_scheduler_has_virtual_group()) {
  313. mali_group_delete(virtual_group);
  314. }
  315. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
  316. mali_group_delete(group);
  317. }
  318. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) {
  319. mali_group_delete(group);
  320. }
  321. }
  322. MALI_STATIC_INLINE void mali_pp_scheduler_disable_empty_virtual(void)
  323. {
  324. MALI_ASSERT_GROUP_LOCKED(virtual_group);
  325. if (mali_group_virtual_disable_if_empty(virtual_group)) {
  326. MALI_DEBUG_PRINT(4, ("Disabling empty virtual group\n"));
  327. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
  328. virtual_group_state = VIRTUAL_GROUP_DISABLED;
  329. }
  330. }
  331. MALI_STATIC_INLINE void mali_pp_scheduler_enable_empty_virtual(void)
  332. {
  333. MALI_ASSERT_GROUP_LOCKED(virtual_group);
  334. if (mali_group_virtual_enable_if_empty(virtual_group)) {
  335. MALI_DEBUG_PRINT(4, ("Re-enabling empty virtual group\n"));
  336. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_DISABLED == virtual_group_state);
  337. virtual_group_state = VIRTUAL_GROUP_IDLE;
  338. }
  339. }
  340. static struct mali_pp_job *mali_pp_scheduler_get_job(struct mali_pp_scheduler_job_queue *queue)
  341. {
  342. struct mali_pp_job *job = NULL;
  343. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  344. MALI_DEBUG_ASSERT_POINTER(queue);
  345. /* Check if we have a normal priority job. */
  346. if (!_mali_osk_list_empty(&queue->normal_pri)) {
  347. MALI_DEBUG_ASSERT(queue->depth > 0);
  348. job = _MALI_OSK_LIST_ENTRY(queue->normal_pri.next, struct mali_pp_job, list);
  349. }
  350. /* Prefer normal priority job if it is in progress. */
  351. if (NULL != job && 0 < job->sub_jobs_started) {
  352. return job;
  353. }
  354. /* Check if we have a high priority job. */
  355. if (!_mali_osk_list_empty(&queue->high_pri)) {
  356. MALI_DEBUG_ASSERT(queue->depth > 0);
  357. job = _MALI_OSK_LIST_ENTRY(queue->high_pri.next, struct mali_pp_job, list);
  358. }
  359. return job;
  360. }
  361. /**
  362. * Returns a physical job if a physical job is ready to run
  363. */
  364. MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_physical_job(void)
  365. {
  366. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  367. return mali_pp_scheduler_get_job(&job_queue);
  368. }
  369. MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_physical_job(struct mali_pp_job *job)
  370. {
  371. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  372. MALI_DEBUG_ASSERT(job_queue.depth > 0);
  373. /* Remove job from queue */
  374. if (!mali_pp_job_has_unstarted_sub_jobs(job)) {
  375. /* All sub jobs have been started: remove job from queue */
  376. _mali_osk_list_delinit(&job->list);
  377. _mali_osk_list_delinit(&job->session_fb_lookup_list);
  378. }
  379. --job_queue.depth;
  380. }
  381. /**
  382. * Returns a virtual job if a virtual job is ready to run
  383. */
  384. MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_virtual_job(void)
  385. {
  386. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  387. MALI_DEBUG_ASSERT_POINTER(virtual_group);
  388. return mali_pp_scheduler_get_job(&virtual_job_queue);
  389. }
  390. MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_virtual_job(struct mali_pp_job *job)
  391. {
  392. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  393. MALI_DEBUG_ASSERT(virtual_job_queue.depth > 0);
  394. /* Remove job from queue */
  395. _mali_osk_list_delinit(&job->list);
  396. _mali_osk_list_delinit(&job->session_fb_lookup_list);
  397. --virtual_job_queue.depth;
  398. }
  399. /**
  400. * Checks if the criteria is met for removing a physical core from virtual group
  401. */
  402. MALI_STATIC_INLINE mali_bool mali_pp_scheduler_can_move_virtual_to_physical(void)
  403. {
  404. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  405. MALI_DEBUG_ASSERT(mali_pp_scheduler_has_virtual_group());
  406. MALI_ASSERT_GROUP_LOCKED(virtual_group);
  407. /*
  408. * The criteria for taking out a physical group from a virtual group are the following:
  409. * - There virtual group is idle
  410. * - There are currently no physical groups (idle and working)
  411. * - There are physical jobs to be scheduled
  412. */
  413. return (VIRTUAL_GROUP_IDLE == virtual_group_state) &&
  414. _mali_osk_list_empty(&group_list_idle) &&
  415. _mali_osk_list_empty(&group_list_working) &&
  416. (NULL != mali_pp_scheduler_get_physical_job());
  417. }
  418. MALI_STATIC_INLINE struct mali_group *mali_pp_scheduler_acquire_physical_group(void)
  419. {
  420. MALI_ASSERT_PP_SCHEDULER_LOCKED();
  421. if (!_mali_osk_list_empty(&group_list_idle)) {
  422. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from idle list.\n"));
  423. return _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list);
  424. } else if (mali_pp_scheduler_has_virtual_group()) {
  425. MALI_ASSERT_GROUP_LOCKED(virtual_group);
  426. if (mali_pp_scheduler_can_move_virtual_to_physical()) {
  427. struct mali_group *group;
  428. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from virtual group.\n"));
  429. group = mali_group_acquire_group(virtual_group);
  430. if (mali_pp_scheduler_has_virtual_group()) {
  431. mali_pp_scheduler_disable_empty_virtual();
  432. }
  433. return group;
  434. }
  435. }
  436. return NULL;
  437. }
  438. static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job, mali_bool deferred)
  439. {
  440. if (MALI_FALSE == mali_pp_job_use_no_notification(job)) {
  441. u32 i;
  442. u32 num_counters_to_copy;
  443. mali_bool success = mali_pp_job_was_success(job);
  444. _mali_uk_pp_job_finished_s *jobres = job->finished_notification->result_buffer;
  445. _mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
  446. jobres->user_job_ptr = mali_pp_job_get_user_id(job);
  447. if (MALI_TRUE == success) {
  448. jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
  449. } else {
  450. jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
  451. }
  452. if (mali_pp_job_is_virtual(job)) {
  453. num_counters_to_copy = num_cores; /* Number of physical cores available */
  454. } else {
  455. num_counters_to_copy = mali_pp_job_get_sub_job_count(job);
  456. }
  457. for (i = 0; i < num_counters_to_copy; i++) {
  458. jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i);
  459. jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i);
  460. jobres->perf_counter_src0 = mali_pp_job_get_pp_counter_global_src0();
  461. jobres->perf_counter_src1 = mali_pp_job_get_pp_counter_global_src1();
  462. }
  463. mali_session_send_notification(mali_pp_job_get_session(job), job->finished_notification);
  464. job->finished_notification = NULL;
  465. }
  466. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  467. if (MALI_TRUE == deferred) {
  468. /* The deletion of the job object (releasing sync refs etc) must be done in a different context */
  469. mali_pp_scheduler_deferred_job_delete(job);
  470. } else {
  471. mali_pp_job_delete(job);
  472. }
  473. #else
  474. MALI_DEBUG_ASSERT(MALI_FALSE == deferred); /* no use cases need this in this configuration */
  475. mali_pp_job_delete(job);
  476. #endif
  477. }
  478. static void mali_pp_scheduler_finalize_job(struct mali_pp_job * job)
  479. {
  480. /* This job object should not be on any lists. */
  481. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
  482. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
  483. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
  484. /* Send notification back to user space */
  485. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  486. mali_pp_scheduler_return_job_to_user(job, MALI_TRUE);
  487. #else
  488. mali_pp_scheduler_return_job_to_user(job, MALI_FALSE);
  489. #endif
  490. #if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY)
  491. if (_MALI_PP_JOB_FLAG_IS_WINDOW_SURFACE & job->uargs.flags) {
  492. _mali_osk_atomic_inc(&job->session->number_of_window_jobs);
  493. }
  494. #endif
  495. mali_pp_scheduler_job_completed();
  496. }
  497. void mali_pp_scheduler_schedule(void)
  498. {
  499. struct mali_group* physical_groups_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
  500. struct mali_pp_job* physical_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
  501. u32 physical_sub_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
  502. int num_physical_jobs_to_start = 0;
  503. int i;
  504. if (mali_pp_scheduler_has_virtual_group()) {
  505. /* Lock the virtual group since we might have to grab physical groups. */
  506. mali_group_lock(virtual_group);
  507. }
  508. mali_pp_scheduler_lock();
  509. if (pause_count > 0) {
  510. /* Scheduler is suspended, don't schedule any jobs. */
  511. mali_pp_scheduler_unlock();
  512. if (mali_pp_scheduler_has_virtual_group()) {
  513. mali_group_unlock(virtual_group);
  514. }
  515. return;
  516. }
  517. /* Find physical job(s) to schedule first. */
  518. while (1) {
  519. struct mali_group *group;
  520. struct mali_pp_job *job;
  521. u32 sub_job;
  522. job = mali_pp_scheduler_get_physical_job();
  523. if (NULL == job) {
  524. break; /* No job, early out. */
  525. }
  526. if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) &&
  527. mali_pp_job_is_large_and_unstarted(job) && !_mali_osk_list_empty(&group_list_working)) {
  528. /* Since not all groups are idle, don't schedule yet. */
  529. break;
  530. }
  531. MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job));
  532. MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
  533. MALI_DEBUG_ASSERT(1 <= mali_pp_job_get_sub_job_count(job));
  534. /* Acquire a physical group, either from the idle list or from the virtual group.
  535. * In case the group was acquired from the virtual group, it's state will be
  536. * LEAVING_VIRTUAL and must be set to IDLE before it can be used. */
  537. group = mali_pp_scheduler_acquire_physical_group();
  538. if (NULL == group) {
  539. /* Could not get a group to run the job on, early out. */
  540. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: No more physical groups available.\n"));
  541. break;
  542. }
  543. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquired physical group %p.\n", group));
  544. /* Mark sub job as started. */
  545. sub_job = mali_pp_job_get_first_unstarted_sub_job(job);
  546. mali_pp_job_mark_sub_job_started(job, sub_job);
  547. /* Remove job from queue (if this was the last sub job). */
  548. mali_pp_scheduler_dequeue_physical_job(job);
  549. /* Move group to working list. */
  550. _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_working);
  551. /* Keep track of this group, so that we actually can start the job once we are done with the scheduler lock we are now holding. */
  552. physical_groups_to_start[num_physical_jobs_to_start] = group;
  553. physical_jobs_to_start[num_physical_jobs_to_start] = job;
  554. physical_sub_jobs_to_start[num_physical_jobs_to_start] = sub_job;
  555. ++num_physical_jobs_to_start;
  556. MALI_DEBUG_ASSERT(num_physical_jobs_to_start < MALI_MAX_NUMBER_OF_PP_GROUPS);
  557. }
  558. if (mali_pp_scheduler_has_virtual_group()) {
  559. if (VIRTUAL_GROUP_IDLE == virtual_group_state) {
  560. /* We have a virtual group and it is idle. */
  561. struct mali_pp_job *job;
  562. /* Find a virtual job we can start. */
  563. job = mali_pp_scheduler_get_virtual_job();
  564. if (NULL != job) {
  565. MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job));
  566. MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
  567. MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job));
  568. /* Mark the one and only sub job as started. */
  569. mali_pp_job_mark_sub_job_started(job, 0);
  570. /* Remove job from queue. */
  571. mali_pp_scheduler_dequeue_virtual_job(job);
  572. /* Virtual group is now working. */
  573. virtual_group_state = VIRTUAL_GROUP_WORKING;
  574. /* We no longer need the scheduler lock, but we still need the virtual lock
  575. * in order to start the virtual job. */
  576. mali_pp_scheduler_unlock();
  577. /* Start job. */
  578. mali_group_start_pp_job(virtual_group, job, 0);
  579. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from schedule).\n",
  580. mali_pp_job_get_id(job), job, 1,
  581. mali_pp_job_get_sub_job_count(job)));
  582. mali_group_unlock(virtual_group);
  583. } else {
  584. /* No virtual job to start. */
  585. mali_pp_scheduler_unlock();
  586. mali_group_unlock(virtual_group);
  587. }
  588. } else {
  589. /* We have a virtual group, but it is busy or disabled. */
  590. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE != virtual_group_state);
  591. mali_pp_scheduler_unlock();
  592. mali_group_unlock(virtual_group);
  593. }
  594. } else {
  595. /* There is no virtual group. */
  596. mali_pp_scheduler_unlock();
  597. }
  598. /* We have now released the scheduler lock, and we are ready to start the physical jobs.
  599. * The reason we want to wait until we have released the scheduler lock is that job start
  600. * may take quite a bit of time (many registers have to be written). This will allow new
  601. * jobs from user space to come in, and post-processing of other PP jobs to happen at the
  602. * same time as we start jobs. */
  603. for (i = 0; i < num_physical_jobs_to_start; i++) {
  604. struct mali_group *group = physical_groups_to_start[i];
  605. struct mali_pp_job *job = physical_jobs_to_start[i];
  606. u32 sub_job = physical_sub_jobs_to_start[i];
  607. MALI_DEBUG_ASSERT_POINTER(group);
  608. MALI_DEBUG_ASSERT_POINTER(job);
  609. MALI_DEBUG_ASSERT(!mali_group_is_virtual(group));
  610. MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job));
  611. mali_group_lock(group);
  612. /* Set state to IDLE if group was acquired from the virtual group. */
  613. group->state = MALI_GROUP_STATE_IDLE;
  614. mali_group_start_pp_job(group, job, sub_job);
  615. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from schedule).\n",
  616. mali_pp_job_get_id(job), job, sub_job + 1,
  617. mali_pp_job_get_sub_job_count(job)));
  618. mali_group_unlock(group);
  619. }
  620. }
  621. /**
  622. * Set group idle.
  623. *
  624. * If @ref group is the virtual group, nothing is done since the virtual group should be idle
  625. * already.
  626. *
  627. * If @ref group is a physical group we rejoin the virtual group, if it exists. If not, we move the
  628. * physical group to the idle list.
  629. *
  630. * @note The group and the scheduler must both be locked when entering this function. Both will be
  631. * unlocked before exiting.
  632. *
  633. * @param group The group to set idle.
  634. */
  635. static void mali_pp_scheduler_set_group_idle_and_unlock(struct mali_group *group)
  636. {
  637. MALI_DEBUG_ASSERT_POINTER(group);
  638. MALI_ASSERT_GROUP_LOCKED(group);
  639. MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
  640. if (mali_group_is_virtual(group)) {
  641. /* The virtual group should have been set to non-working already. */
  642. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
  643. mali_pp_scheduler_unlock();
  644. mali_group_unlock(group);
  645. return;
  646. } else {
  647. if (mali_pp_scheduler_has_virtual_group()) {
  648. /* Rejoin virtual group. */
  649. /* We're no longer needed on the scheduler list. */
  650. _mali_osk_list_delinit(&(group->pp_scheduler_list));
  651. /* Make sure no interrupts are handled for this group during the transition
  652. * from physical to virtual. */
  653. group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
  654. mali_pp_scheduler_unlock();
  655. mali_group_unlock(group);
  656. mali_group_lock(virtual_group);
  657. if (mali_pp_scheduler_has_virtual_group()) {
  658. mali_pp_scheduler_enable_empty_virtual();
  659. }
  660. /* We need to recheck the group state since it is possible that someone has
  661. * modified the group before we locked the virtual group. */
  662. if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) {
  663. mali_group_add_group(virtual_group, group, MALI_TRUE);
  664. }
  665. mali_group_unlock(virtual_group);
  666. } else {
  667. /* Move physical group back to idle list. */
  668. _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
  669. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  670. trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0);
  671. #endif
  672. mali_pp_scheduler_unlock();
  673. mali_group_unlock(group);
  674. }
  675. }
  676. }
  677. /**
  678. * Schedule job on locked group.
  679. *
  680. * @note The group and the scheduler must both be locked when entering this function. Both will be
  681. * unlocked before exiting.
  682. *
  683. * @param group The group to schedule on.
  684. */
  685. static void mali_pp_scheduler_schedule_on_group_and_unlock(struct mali_group *group)
  686. {
  687. MALI_DEBUG_ASSERT_POINTER(group);
  688. MALI_ASSERT_GROUP_LOCKED(group);
  689. MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
  690. if (mali_group_is_virtual(group)) {
  691. /* Now that the virtual group is idle, check if we should reconfigure. */
  692. struct mali_pp_job *virtual_job = NULL;
  693. struct mali_pp_job *physical_job = NULL;
  694. struct mali_group *physical_group = NULL;
  695. u32 physical_sub_job = 0;
  696. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
  697. if (mali_pp_scheduler_can_move_virtual_to_physical()) {
  698. /* There is a runnable physical job and we can acquire a physical group. */
  699. physical_job = mali_pp_scheduler_get_physical_job();
  700. MALI_DEBUG_ASSERT_POINTER(physical_job);
  701. MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(physical_job));
  702. /* Mark sub job as started. */
  703. physical_sub_job = mali_pp_job_get_first_unstarted_sub_job(physical_job);
  704. mali_pp_job_mark_sub_job_started(physical_job, physical_sub_job);
  705. /* Remove job from queue (if this was the last sub job). */
  706. mali_pp_scheduler_dequeue_physical_job(physical_job);
  707. /* Acquire a physical group from the virtual group. Its state will
  708. * be LEAVING_VIRTUAL and must be set to IDLE before it can be
  709. * used. */
  710. physical_group = mali_group_acquire_group(virtual_group);
  711. /* Move physical group to the working list, as we will soon start a job on it. */
  712. _mali_osk_list_move(&(physical_group->pp_scheduler_list), &group_list_working);
  713. mali_pp_scheduler_disable_empty_virtual();
  714. }
  715. /* Get next virtual job. */
  716. virtual_job = mali_pp_scheduler_get_virtual_job();
  717. if (NULL != virtual_job && VIRTUAL_GROUP_IDLE == virtual_group_state) {
  718. /* There is a runnable virtual job. */
  719. MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(virtual_job));
  720. MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(virtual_job));
  721. MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(virtual_job));
  722. mali_pp_job_mark_sub_job_started(virtual_job, 0);
  723. /* Remove job from queue. */
  724. mali_pp_scheduler_dequeue_virtual_job(virtual_job);
  725. /* Virtual group is now working. */
  726. virtual_group_state = VIRTUAL_GROUP_WORKING;
  727. mali_pp_scheduler_unlock();
  728. /* Start job. */
  729. mali_group_start_pp_job(group, virtual_job, 0);
  730. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from job_done).\n",
  731. mali_pp_job_get_id(virtual_job), virtual_job, 1,
  732. mali_pp_job_get_sub_job_count(virtual_job)));
  733. } else {
  734. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  735. trace_gpu_sched_switch("Mali_Virtual_PP", sched_clock(), 0, 0, 0);
  736. #endif
  737. mali_pp_scheduler_unlock();
  738. }
  739. /* Releasing the virtual group lock that was held when entering the function. */
  740. mali_group_unlock(group);
  741. /* Start a physical job (if we acquired a physical group earlier). */
  742. if (NULL != physical_job && NULL != physical_group) {
  743. mali_group_lock(physical_group);
  744. /* Change the group state from LEAVING_VIRTUAL to IDLE to complete the transition. */
  745. physical_group->state = MALI_GROUP_STATE_IDLE;
  746. /* Start job. */
  747. mali_group_start_pp_job(physical_group, physical_job, physical_sub_job);
  748. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n",
  749. mali_pp_job_get_id(physical_job), physical_job, physical_sub_job + 1,
  750. mali_pp_job_get_sub_job_count(physical_job)));
  751. mali_group_unlock(physical_group);
  752. }
  753. } else {
  754. /* Physical group. */
  755. struct mali_pp_job *job = NULL;
  756. u32 sub_job = 0;
  757. job = mali_pp_scheduler_get_physical_job();
  758. if (NULL != job) {
  759. /* There is a runnable physical job. */
  760. MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
  761. /* Mark sub job as started. */
  762. sub_job = mali_pp_job_get_first_unstarted_sub_job(job);
  763. mali_pp_job_mark_sub_job_started(job, sub_job);
  764. /* Remove job from queue (if this was the last sub job). */
  765. mali_pp_scheduler_dequeue_physical_job(job);
  766. mali_pp_scheduler_unlock();
  767. /* Group is already on the working list, so start the new job. */
  768. mali_group_start_pp_job(group, job, sub_job);
  769. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n",
  770. mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job)));
  771. mali_group_unlock(group);
  772. } else {
  773. mali_pp_scheduler_set_group_idle_and_unlock(group);
  774. }
  775. }
  776. }
  777. void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success, mali_bool in_upper_half)
  778. {
  779. mali_bool job_is_done = MALI_FALSE;
  780. mali_bool schedule_on_group = MALI_FALSE;
  781. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  782. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) part %u/%u completed (%s).\n",
  783. mali_pp_job_is_virtual(job) ? "Virtual" : "Physical",
  784. mali_pp_job_get_id(job),
  785. job, sub_job + 1,
  786. mali_pp_job_get_sub_job_count(job),
  787. success ? "success" : "failure"));
  788. MALI_ASSERT_GROUP_LOCKED(group);
  789. mali_pp_scheduler_lock();
  790. mali_pp_job_mark_sub_job_completed(job, success);
  791. MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job) == mali_group_is_virtual(group));
  792. job_is_done = mali_pp_job_is_complete(job);
  793. if (job_is_done) {
  794. /* Job is removed from these lists when the last sub job is scheduled. */
  795. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
  796. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
  797. /* Remove job from session list. */
  798. _mali_osk_list_delinit(&job->session_list);
  799. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: All parts completed for %s job %u (0x%08X).\n",
  800. mali_pp_job_is_virtual(job) ? "virtual" : "physical",
  801. mali_pp_job_get_id(job), job));
  802. mali_pp_scheduler_unlock();
  803. /* Release tracker. If other trackers are waiting on this tracker, this could
  804. * trigger activation. The returned scheduling mask can be used to determine if we
  805. * have to schedule GP, PP or both. */
  806. schedule_mask = mali_timeline_tracker_release(&job->tracker);
  807. mali_pp_scheduler_lock();
  808. }
  809. if (mali_group_is_virtual(group)) {
  810. /* Obey the policy. */
  811. virtual_group_state = VIRTUAL_GROUP_IDLE;
  812. }
  813. /* If paused, then this was the last job, so wake up sleeping workers and return. */
  814. if (pause_count > 0) {
  815. /* Wake up sleeping workers. Their wake-up condition is that
  816. * num_slots == num_slots_idle, so unless we are done working, no
  817. * threads will actually be woken up.
  818. */
  819. if (!mali_group_is_virtual(group)) {
  820. /* Move physical group to idle list. */
  821. _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
  822. }
  823. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  824. trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0);
  825. #endif
  826. _mali_osk_wait_queue_wake_up(pp_scheduler_working_wait_queue);
  827. mali_pp_scheduler_unlock();
  828. mali_group_unlock(group);
  829. if (job_is_done) {
  830. /* Return job to user and delete it. */
  831. mali_pp_scheduler_finalize_job(job);
  832. }
  833. /* A GP job might be queued by tracker release above,
  834. * make sure GP scheduler gets a chance to schedule this (if possible)
  835. */
  836. mali_scheduler_schedule_from_mask(schedule_mask & ~MALI_SCHEDULER_MASK_PP, in_upper_half);
  837. return;
  838. }
  839. /* Since this group just finished running a job, we can reschedule a new job on it
  840. * immediately. */
  841. /* By default, don't schedule on group. */
  842. schedule_on_group = MALI_FALSE;
  843. if (mali_group_is_virtual(group)) {
  844. /* Always schedule immediately on virtual group. */
  845. schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
  846. schedule_on_group = MALI_TRUE;
  847. } else if (0 < job_queue.depth && (!mali_scheduler_mask_is_set(schedule_mask, MALI_SCHEDULER_MASK_PP) || _mali_osk_list_empty(&group_list_idle))) {
  848. struct mali_pp_job *next_job = NULL;
  849. next_job = mali_pp_scheduler_get_physical_job();
  850. MALI_DEBUG_ASSERT_POINTER(next_job);
  851. /* If no new jobs have been queued or if this group is the only idle group, we can
  852. * schedule immediately on this group, unless we are GP bound and the next job would
  853. * benefit from all its sub jobs being started concurrently. */
  854. if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) && mali_pp_job_is_large_and_unstarted(next_job)) {
  855. /* We are GP bound and the job would benefit from all sub jobs being started
  856. * concurrently. Postpone scheduling until after group has been unlocked. */
  857. schedule_mask |= MALI_SCHEDULER_MASK_PP;
  858. schedule_on_group = MALI_FALSE;
  859. } else {
  860. /* Schedule job immediately since we are not GP bound. */
  861. schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
  862. schedule_on_group = MALI_TRUE;
  863. }
  864. }
  865. if (schedule_on_group) {
  866. /* Schedule a new job on this group. */
  867. mali_pp_scheduler_schedule_on_group_and_unlock(group);
  868. } else {
  869. /* Set group idle. Will rejoin virtual group, under appropriate conditions. */
  870. mali_pp_scheduler_set_group_idle_and_unlock(group);
  871. }
  872. if (!schedule_on_group || MALI_SCHEDULER_MASK_EMPTY != schedule_mask) {
  873. if (MALI_SCHEDULER_MASK_PP & schedule_mask) {
  874. /* Schedule PP directly. */
  875. mali_pp_scheduler_schedule();
  876. schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
  877. }
  878. /* Schedule other jobs that were activated. */
  879. mali_scheduler_schedule_from_mask(schedule_mask, in_upper_half);
  880. }
  881. if (job_is_done) {
  882. /* Return job to user and delete it. */
  883. mali_pp_scheduler_finalize_job(job);
  884. }
  885. }
  886. void mali_pp_scheduler_suspend(void)
  887. {
  888. mali_pp_scheduler_lock();
  889. pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */
  890. mali_pp_scheduler_unlock();
  891. /* Go to sleep. When woken up again (in mali_pp_scheduler_job_done), the
  892. * mali_pp_scheduler_suspended() function will be called. This will return true
  893. * if state is idle and pause_count > 0, so if the core is active this
  894. * will not do anything.
  895. */
  896. _mali_osk_wait_queue_wait_event(pp_scheduler_working_wait_queue, mali_pp_scheduler_is_suspended, NULL);
  897. }
  898. void mali_pp_scheduler_resume(void)
  899. {
  900. mali_pp_scheduler_lock();
  901. pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */
  902. mali_pp_scheduler_unlock();
  903. if (0 == pause_count) {
  904. mali_pp_scheduler_schedule();
  905. }
  906. }
  907. mali_timeline_point mali_pp_scheduler_submit_job(struct mali_session_data *session, struct mali_pp_job *job)
  908. {
  909. mali_timeline_point point;
  910. u32 fb_lookup_id = 0;
  911. MALI_DEBUG_ASSERT_POINTER(session);
  912. MALI_DEBUG_ASSERT_POINTER(job);
  913. mali_pp_scheduler_lock();
  914. fb_lookup_id = mali_pp_job_get_fb_lookup_id(job);
  915. MALI_DEBUG_ASSERT(MALI_PP_JOB_FB_LOOKUP_LIST_SIZE > fb_lookup_id);
  916. /* Adding job to the lookup list used to quickly discard writeback units of queued jobs. */
  917. _mali_osk_list_addtail(&job->session_fb_lookup_list, &session->pp_job_fb_lookup_list[fb_lookup_id]);
  918. mali_pp_scheduler_unlock();
  919. mali_pp_scheduler_job_queued();
  920. /* Add job to Timeline system. */
  921. point = mali_timeline_system_add_tracker(session->timeline_system, &job->tracker, MALI_TIMELINE_PP);
  922. return point;
  923. }
  924. _mali_osk_errcode_t _mali_ukk_pp_start_job(void *ctx, _mali_uk_pp_start_job_s *uargs)
  925. {
  926. struct mali_session_data *session;
  927. struct mali_pp_job *job;
  928. mali_timeline_point point;
  929. u32 __user *timeline_point_ptr = NULL;
  930. MALI_DEBUG_ASSERT_POINTER(uargs);
  931. MALI_DEBUG_ASSERT_POINTER(ctx);
  932. session = (struct mali_session_data*)ctx;
  933. job = mali_pp_job_create(session, uargs, mali_scheduler_get_new_id());
  934. if (NULL == job) {
  935. MALI_PRINT_ERROR(("Failed to create PP job.\n"));
  936. return _MALI_OSK_ERR_NOMEM;
  937. }
  938. timeline_point_ptr = (u32 __user *) job->uargs.timeline_point_ptr;
  939. point = mali_pp_scheduler_submit_job(session, job);
  940. job = NULL;
  941. if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) {
  942. /* Let user space know that something failed after the job was started. */
  943. return _MALI_OSK_ERR_ITEM_NOT_FOUND;
  944. }
  945. return _MALI_OSK_ERR_OK;
  946. }
  947. _mali_osk_errcode_t _mali_ukk_pp_and_gp_start_job(void *ctx, _mali_uk_pp_and_gp_start_job_s *uargs)
  948. {
  949. struct mali_session_data *session;
  950. _mali_uk_pp_and_gp_start_job_s kargs;
  951. struct mali_pp_job *pp_job;
  952. struct mali_gp_job *gp_job;
  953. u32 __user *timeline_point_ptr = NULL;
  954. mali_timeline_point point;
  955. MALI_DEBUG_ASSERT_POINTER(ctx);
  956. MALI_DEBUG_ASSERT_POINTER(uargs);
  957. session = (struct mali_session_data *) ctx;
  958. if (0 != _mali_osk_copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_and_gp_start_job_s))) {
  959. return _MALI_OSK_ERR_NOMEM;
  960. }
  961. pp_job = mali_pp_job_create(session, kargs.pp_args, mali_scheduler_get_new_id());
  962. if (NULL == pp_job) {
  963. MALI_PRINT_ERROR(("Failed to create PP job.\n"));
  964. return _MALI_OSK_ERR_NOMEM;
  965. }
  966. gp_job = mali_gp_job_create(session, kargs.gp_args, mali_scheduler_get_new_id(), mali_pp_job_get_tracker(pp_job));
  967. if (NULL == gp_job) {
  968. MALI_PRINT_ERROR(("Failed to create GP job.\n"));
  969. mali_pp_job_delete(pp_job);
  970. return _MALI_OSK_ERR_NOMEM;
  971. }
  972. timeline_point_ptr = (u32 __user *) pp_job->uargs.timeline_point_ptr;
  973. /* Submit GP job. */
  974. mali_gp_scheduler_submit_job(session, gp_job);
  975. gp_job = NULL;
  976. /* Submit PP job. */
  977. point = mali_pp_scheduler_submit_job(session, pp_job);
  978. pp_job = NULL;
  979. if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) {
  980. /* Let user space know that something failed after the jobs were started. */
  981. return _MALI_OSK_ERR_ITEM_NOT_FOUND;
  982. }
  983. return _MALI_OSK_ERR_OK;
  984. }
  985. _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args)
  986. {
  987. MALI_DEBUG_ASSERT_POINTER(args);
  988. MALI_DEBUG_ASSERT_POINTER(args->ctx);
  989. args->number_of_total_cores = num_cores;
  990. args->number_of_enabled_cores = enabled_cores;
  991. return _MALI_OSK_ERR_OK;
  992. }
  993. u32 mali_pp_scheduler_get_num_cores_total(void)
  994. {
  995. return num_cores;
  996. }
  997. u32 mali_pp_scheduler_get_num_cores_enabled(void)
  998. {
  999. return enabled_cores;
  1000. }
  1001. _mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args)
  1002. {
  1003. MALI_DEBUG_ASSERT_POINTER(args);
  1004. MALI_DEBUG_ASSERT_POINTER(args->ctx);
  1005. args->version = pp_version;
  1006. return _MALI_OSK_ERR_OK;
  1007. }
  1008. void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args)
  1009. {
  1010. struct mali_session_data *session;
  1011. struct mali_pp_job *job;
  1012. struct mali_pp_job *tmp;
  1013. u32 fb_lookup_id;
  1014. MALI_DEBUG_ASSERT_POINTER(args);
  1015. MALI_DEBUG_ASSERT_POINTER(args->ctx);
  1016. session = (struct mali_session_data*)args->ctx;
  1017. fb_lookup_id = args->fb_id & MALI_PP_JOB_FB_LOOKUP_LIST_MASK;
  1018. mali_pp_scheduler_lock();
  1019. /* Iterate over all jobs for given frame builder_id. */
  1020. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &session->pp_job_fb_lookup_list[fb_lookup_id], struct mali_pp_job, session_fb_lookup_list) {
  1021. MALI_DEBUG_CODE(u32 disable_mask = 0);
  1022. if (mali_pp_job_get_frame_builder_id(job) == (u32) args->fb_id) {
  1023. MALI_DEBUG_CODE(disable_mask |= 0xD<<(4*3));
  1024. if (args->wb0_memory == job->uargs.wb0_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
  1025. MALI_DEBUG_CODE(disable_mask |= 0x1<<(4*1));
  1026. mali_pp_job_disable_wb0(job);
  1027. }
  1028. if (args->wb1_memory == job->uargs.wb1_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
  1029. MALI_DEBUG_CODE(disable_mask |= 0x2<<(4*2));
  1030. mali_pp_job_disable_wb1(job);
  1031. }
  1032. if (args->wb2_memory == job->uargs.wb2_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
  1033. MALI_DEBUG_CODE(disable_mask |= 0x3<<(4*3));
  1034. mali_pp_job_disable_wb2(job);
  1035. }
  1036. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disable WB: 0x%X.\n", disable_mask));
  1037. } else {
  1038. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Disable WB mismatching FB.\n"));
  1039. }
  1040. }
  1041. mali_pp_scheduler_unlock();
  1042. }
  1043. void mali_pp_scheduler_abort_session(struct mali_session_data *session)
  1044. {
  1045. u32 i = 0;
  1046. struct mali_pp_job *job, *tmp_job;
  1047. struct mali_group *group, *tmp_group;
  1048. struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
  1049. _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs);
  1050. MALI_DEBUG_ASSERT_POINTER(session);
  1051. MALI_DEBUG_ASSERT(session->is_aborting);
  1052. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborting all jobs from session 0x%08X.\n", session));
  1053. mali_pp_scheduler_lock();
  1054. /* Find all jobs from the aborting session. */
  1055. _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &session->pp_job_list, struct mali_pp_job, session_list) {
  1056. /* Remove job from queue. */
  1057. if (mali_pp_job_is_virtual(job)) {
  1058. MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job));
  1059. if (0 == mali_pp_job_get_first_unstarted_sub_job(job)) {
  1060. --virtual_job_queue.depth;
  1061. }
  1062. } else {
  1063. job_queue.depth -= mali_pp_job_get_sub_job_count(job) - mali_pp_job_get_first_unstarted_sub_job(job);
  1064. }
  1065. _mali_osk_list_delinit(&job->list);
  1066. _mali_osk_list_delinit(&job->session_fb_lookup_list);
  1067. mali_pp_job_mark_unstarted_failed(job);
  1068. if (mali_pp_job_is_complete(job)) {
  1069. /* Job is complete, remove from session list. */
  1070. _mali_osk_list_delinit(&job->session_list);
  1071. /* Move job to local list for release and deletion. */
  1072. _mali_osk_list_add(&job->list, &removed_jobs);
  1073. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborted PP job %u (0x%08X).\n", mali_pp_job_get_id(job), job));
  1074. } else {
  1075. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Keeping partially started PP job %u (0x%08X) in session.\n", mali_pp_job_get_id(job), job));
  1076. }
  1077. }
  1078. _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_working, struct mali_group, pp_scheduler_list) {
  1079. groups[i++] = group;
  1080. }
  1081. _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_idle, struct mali_group, pp_scheduler_list) {
  1082. groups[i++] = group;
  1083. }
  1084. mali_pp_scheduler_unlock();
  1085. /* Release and delete all found jobs from the aborting session. */
  1086. _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &removed_jobs, struct mali_pp_job, list) {
  1087. mali_timeline_tracker_release(&job->tracker);
  1088. mali_pp_job_delete(job);
  1089. mali_pp_scheduler_job_completed();
  1090. }
  1091. /* Abort any running jobs from the session. */
  1092. while (i > 0) {
  1093. mali_group_abort_session(groups[--i], session);
  1094. }
  1095. if (mali_pp_scheduler_has_virtual_group()) {
  1096. mali_group_abort_session(virtual_group, session);
  1097. }
  1098. }
  1099. static mali_bool mali_pp_scheduler_is_suspended(void *data)
  1100. {
  1101. mali_bool ret;
  1102. /* This callback does not use the data pointer. */
  1103. MALI_IGNORE(data);
  1104. mali_pp_scheduler_lock();
  1105. ret = pause_count > 0
  1106. && _mali_osk_list_empty(&group_list_working)
  1107. && VIRTUAL_GROUP_WORKING != virtual_group_state;
  1108. mali_pp_scheduler_unlock();
  1109. return ret;
  1110. }
  1111. struct mali_pp_core *mali_pp_scheduler_get_virtual_pp(void)
  1112. {
  1113. if (mali_pp_scheduler_has_virtual_group()) {
  1114. return mali_group_get_pp_core(virtual_group);
  1115. } else {
  1116. return NULL;
  1117. }
  1118. }
  1119. #if MALI_STATE_TRACKING
  1120. u32 mali_pp_scheduler_dump_state(char *buf, u32 size)
  1121. {
  1122. int n = 0;
  1123. struct mali_group *group;
  1124. struct mali_group *temp;
  1125. n += _mali_osk_snprintf(buf + n, size - n, "PP:\n");
  1126. n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue.normal_pri) ? "empty" : "not empty");
  1127. n += _mali_osk_snprintf(buf + n, size - n, "\tHigh priority queue is %s\n", _mali_osk_list_empty(&job_queue.high_pri) ? "empty" : "not empty");
  1128. n += _mali_osk_snprintf(buf + n, size - n, "\n");
  1129. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) {
  1130. n += mali_group_dump_state(group, buf + n, size - n);
  1131. }
  1132. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
  1133. n += mali_group_dump_state(group, buf + n, size - n);
  1134. }
  1135. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) {
  1136. n += mali_group_dump_state(group, buf + n, size - n);
  1137. }
  1138. if (mali_pp_scheduler_has_virtual_group()) {
  1139. n += mali_group_dump_state(virtual_group, buf + n, size -n);
  1140. }
  1141. n += _mali_osk_snprintf(buf + n, size - n, "\n");
  1142. return n;
  1143. }
  1144. #endif
  1145. /* This function is intended for power on reset of all cores.
  1146. * No locking is done for the list iteration, which can only be safe if the
  1147. * scheduler is paused and all cores idle. That is always the case on init and
  1148. * power on. */
  1149. void mali_pp_scheduler_reset_all_groups(void)
  1150. {
  1151. struct mali_group *group, *temp;
  1152. struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
  1153. s32 i = 0;
  1154. if (mali_pp_scheduler_has_virtual_group()) {
  1155. mali_group_lock(virtual_group);
  1156. mali_group_reset(virtual_group);
  1157. mali_group_unlock(virtual_group);
  1158. }
  1159. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
  1160. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
  1161. mali_pp_scheduler_lock();
  1162. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
  1163. groups[i++] = group;
  1164. }
  1165. mali_pp_scheduler_unlock();
  1166. while (i > 0) {
  1167. group = groups[--i];
  1168. mali_group_lock(group);
  1169. mali_group_reset(group);
  1170. mali_group_unlock(group);
  1171. }
  1172. }
  1173. void mali_pp_scheduler_zap_all_active(struct mali_session_data *session)
  1174. {
  1175. struct mali_group *group, *temp;
  1176. struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
  1177. s32 i = 0;
  1178. if (mali_pp_scheduler_has_virtual_group()) {
  1179. mali_group_zap_session(virtual_group, session);
  1180. }
  1181. mali_pp_scheduler_lock();
  1182. _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) {
  1183. groups[i++] = group;
  1184. }
  1185. mali_pp_scheduler_unlock();
  1186. while (i > 0) {
  1187. mali_group_zap_session(groups[--i], session);
  1188. }
  1189. }
  1190. /* A pm reference must be taken with _mali_osk_pm_dev_ref_add_no_power_on
  1191. * before calling this function to avoid Mali powering down as HW is accessed.
  1192. */
  1193. static void mali_pp_scheduler_enable_group_internal(struct mali_group *group)
  1194. {
  1195. MALI_DEBUG_ASSERT_POINTER(group);
  1196. mali_group_lock(group);
  1197. if (MALI_GROUP_STATE_DISABLED != group->state) {
  1198. mali_group_unlock(group);
  1199. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already enabled.\n", group));
  1200. return;
  1201. }
  1202. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Enabling PP group %p.\n", group));
  1203. mali_pp_scheduler_lock();
  1204. MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state);
  1205. ++enabled_cores;
  1206. if (mali_pp_scheduler_has_virtual_group()) {
  1207. mali_bool update_hw;
  1208. /* Add group to virtual group. */
  1209. _mali_osk_list_delinit(&(group->pp_scheduler_list));
  1210. group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
  1211. mali_pp_scheduler_unlock();
  1212. mali_group_unlock(group);
  1213. mali_group_lock(virtual_group);
  1214. update_hw = mali_pm_is_power_on();
  1215. /* Get ref of group domain */
  1216. mali_group_get_pm_domain_ref(group);
  1217. MALI_DEBUG_ASSERT(NULL == group->pm_domain ||
  1218. MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain));
  1219. if (update_hw) {
  1220. mali_group_lock(group);
  1221. mali_group_power_on_group(group);
  1222. mali_group_reset(group);
  1223. mali_group_unlock(group);
  1224. }
  1225. mali_pp_scheduler_enable_empty_virtual();
  1226. mali_group_add_group(virtual_group, group, update_hw);
  1227. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Added to virtual group.\n", group));
  1228. mali_group_unlock(virtual_group);
  1229. } else {
  1230. /* Get ref of group domain */
  1231. mali_group_get_pm_domain_ref(group);
  1232. MALI_DEBUG_ASSERT(NULL == group->pm_domain ||
  1233. MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain));
  1234. /* Put group on idle list. */
  1235. if (mali_pm_is_power_on()) {
  1236. mali_group_power_on_group(group);
  1237. mali_group_reset(group);
  1238. }
  1239. _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
  1240. group->state = MALI_GROUP_STATE_IDLE;
  1241. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Now on idle list.\n", group));
  1242. mali_pp_scheduler_unlock();
  1243. mali_group_unlock(group);
  1244. }
  1245. }
  1246. void mali_pp_scheduler_enable_group(struct mali_group *group)
  1247. {
  1248. MALI_DEBUG_ASSERT_POINTER(group);
  1249. _mali_osk_pm_dev_ref_add_no_power_on();
  1250. mali_pp_scheduler_enable_group_internal(group);
  1251. _mali_osk_pm_dev_ref_dec_no_power_on();
  1252. /* Pick up any jobs that might have been queued if all PP groups were disabled. */
  1253. mali_pp_scheduler_schedule();
  1254. }
  1255. static void mali_pp_scheduler_disable_group_internal(struct mali_group *group)
  1256. {
  1257. if (mali_pp_scheduler_has_virtual_group()) {
  1258. mali_group_lock(virtual_group);
  1259. MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
  1260. if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) {
  1261. /* The group was in the process of being added to the virtual group. We
  1262. * only need to change the state to reverse this. */
  1263. group->state = MALI_GROUP_STATE_LEAVING_VIRTUAL;
  1264. } else if (MALI_GROUP_STATE_IN_VIRTUAL == group->state) {
  1265. /* Remove group from virtual group. The state of the group will be
  1266. * LEAVING_VIRTUAL and the group will not be on any scheduler list. */
  1267. mali_group_remove_group(virtual_group, group);
  1268. mali_pp_scheduler_disable_empty_virtual();
  1269. }
  1270. mali_group_unlock(virtual_group);
  1271. }
  1272. mali_group_lock(group);
  1273. mali_pp_scheduler_lock();
  1274. MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state
  1275. || MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state
  1276. || MALI_GROUP_STATE_DISABLED == group->state);
  1277. if (MALI_GROUP_STATE_DISABLED == group->state) {
  1278. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already disabled.\n", group));
  1279. } else {
  1280. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disabling PP group %p.\n", group));
  1281. --enabled_cores;
  1282. _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_disabled);
  1283. group->state = MALI_GROUP_STATE_DISABLED;
  1284. mali_group_power_off_group(group, MALI_TRUE);
  1285. mali_group_put_pm_domain_ref(group);
  1286. }
  1287. mali_pp_scheduler_unlock();
  1288. mali_group_unlock(group);
  1289. }
  1290. void mali_pp_scheduler_disable_group(struct mali_group *group)
  1291. {
  1292. MALI_DEBUG_ASSERT_POINTER(group);
  1293. mali_pp_scheduler_suspend();
  1294. _mali_osk_pm_dev_ref_add_no_power_on();
  1295. mali_pp_scheduler_disable_group_internal(group);
  1296. _mali_osk_pm_dev_ref_dec_no_power_on();
  1297. mali_pp_scheduler_resume();
  1298. }
  1299. static void mali_pp_scheduler_notify_core_change(u32 num_cores)
  1300. {
  1301. mali_bool done = MALI_FALSE;
  1302. if (mali_is_mali450() || mali_is_mali470()) {
  1303. return;
  1304. }
  1305. /*
  1306. * This function gets a bit complicated because we can't hold the session lock while
  1307. * allocating notification objects.
  1308. */
  1309. while (!done) {
  1310. u32 i;
  1311. u32 num_sessions_alloc;
  1312. u32 num_sessions_with_lock;
  1313. u32 used_notification_objects = 0;
  1314. _mali_osk_notification_t **notobjs;
  1315. /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */
  1316. num_sessions_alloc = mali_session_get_count();
  1317. if (0 == num_sessions_alloc) {
  1318. /* No sessions to report to */
  1319. return;
  1320. }
  1321. notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc);
  1322. if (NULL == notobjs) {
  1323. MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n"));
  1324. /* there is probably no point in trying again, system must be really low on memory and probably unusable now anyway */
  1325. return;
  1326. }
  1327. for (i = 0; i < num_sessions_alloc; i++) {
  1328. notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_NUM_CORE_CHANGE, sizeof(_mali_uk_pp_num_cores_changed_s));
  1329. if (NULL != notobjs[i]) {
  1330. _mali_uk_pp_num_cores_changed_s *data = notobjs[i]->result_buffer;
  1331. data->number_of_enabled_cores = num_cores;
  1332. } else {
  1333. MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure %u)\n", i));
  1334. }
  1335. }
  1336. mali_session_lock();
  1337. /* number of sessions will not change while we hold the lock */
  1338. num_sessions_with_lock = mali_session_get_count();
  1339. if (num_sessions_alloc >= num_sessions_with_lock) {
  1340. /* We have allocated enough notification objects for all the sessions atm */
  1341. struct mali_session_data *session, *tmp;
  1342. MALI_SESSION_FOREACH(session, tmp, link) {
  1343. MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc);
  1344. if (NULL != notobjs[used_notification_objects]) {
  1345. mali_session_send_notification(session, notobjs[used_notification_objects]);
  1346. notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */
  1347. }
  1348. used_notification_objects++;
  1349. }
  1350. done = MALI_TRUE;
  1351. }
  1352. mali_session_unlock();
  1353. /* Delete any remaining/unused notification objects */
  1354. for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) {
  1355. if (NULL != notobjs[used_notification_objects]) {
  1356. _mali_osk_notification_delete(notobjs[used_notification_objects]);
  1357. }
  1358. }
  1359. _mali_osk_free(notobjs);
  1360. }
  1361. }
  1362. static void mali_pp_scheduler_core_scale_up(unsigned int target_core_nr)
  1363. {
  1364. MALI_DEBUG_PRINT(2, ("Requesting %d cores: enabling %d cores\n", target_core_nr, target_core_nr - enabled_cores));
  1365. _mali_osk_pm_dev_ref_add_no_power_on();
  1366. _mali_osk_pm_dev_barrier();
  1367. while (target_core_nr > enabled_cores) {
  1368. /*
  1369. * If there are any cores which do not belong to any domain,
  1370. * then these will always be found at the head of the list and
  1371. * we'll thus enabled these first.
  1372. */
  1373. mali_pp_scheduler_lock();
  1374. if (!_mali_osk_list_empty(&group_list_disabled)) {
  1375. struct mali_group *group;
  1376. group = _MALI_OSK_LIST_ENTRY(group_list_disabled.next, struct mali_group, pp_scheduler_list);
  1377. MALI_DEBUG_ASSERT_POINTER(group);
  1378. MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state);
  1379. mali_pp_scheduler_unlock();
  1380. mali_pp_scheduler_enable_group_internal(group);
  1381. } else {
  1382. mali_pp_scheduler_unlock();
  1383. break; /* no more groups on disabled list */
  1384. }
  1385. }
  1386. _mali_osk_pm_dev_ref_dec_no_power_on();
  1387. mali_pp_scheduler_schedule();
  1388. }
  1389. static void mali_pp_scheduler_core_scale_down(unsigned int target_core_nr)
  1390. {
  1391. MALI_DEBUG_PRINT(2, ("Requesting %d cores: disabling %d cores\n", target_core_nr, enabled_cores - target_core_nr));
  1392. mali_pp_scheduler_suspend();
  1393. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
  1394. _mali_osk_pm_dev_ref_add_no_power_on();
  1395. if (NULL != mali_pmu_get_global_pmu_core()) {
  1396. int i;
  1397. for (i = MALI_MAX_NUMBER_OF_DOMAINS - 1; i >= 0; i--) {
  1398. if (target_core_nr < enabled_cores) {
  1399. struct mali_pm_domain *domain;
  1400. domain = mali_pm_domain_get_from_index(i);
  1401. /* Domain is valid and has pp cores */
  1402. if ((NULL != domain) && (NULL != domain->group_list)) {
  1403. struct mali_group *group;
  1404. MALI_PM_DOMAIN_FOR_EACH_GROUP(group, domain) {
  1405. /* If group is pp core */
  1406. if (NULL != mali_group_get_pp_core(group)) {
  1407. mali_pp_scheduler_disable_group_internal(group);
  1408. if (target_core_nr >= enabled_cores) {
  1409. break;
  1410. }
  1411. }
  1412. }
  1413. }
  1414. } else {
  1415. break;
  1416. }
  1417. }
  1418. }
  1419. /*
  1420. * Didn't find enough cores associated with a power domain,
  1421. * so we need to disable cores which we can't power off with the PMU.
  1422. * Start with physical groups used by the scheduler,
  1423. * then remove physical from virtual if even more groups are needed.
  1424. */
  1425. while (target_core_nr < enabled_cores) {
  1426. mali_pp_scheduler_lock();
  1427. if (!_mali_osk_list_empty(&group_list_idle)) {
  1428. struct mali_group *group;
  1429. group = _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list);
  1430. MALI_DEBUG_ASSERT_POINTER(group);
  1431. mali_pp_scheduler_unlock();
  1432. mali_pp_scheduler_disable_group_internal(group);
  1433. } else {
  1434. mali_pp_scheduler_unlock();
  1435. break; /* No more physical groups */
  1436. }
  1437. }
  1438. if (mali_pp_scheduler_has_virtual_group()) {
  1439. while (target_core_nr < enabled_cores) {
  1440. mali_group_lock(virtual_group);
  1441. if (!_mali_osk_list_empty(&virtual_group->group_list)) {
  1442. struct mali_group *group;
  1443. group = _MALI_OSK_LIST_ENTRY(virtual_group->group_list.next, struct mali_group, group_list);
  1444. MALI_DEBUG_ASSERT_POINTER(group);
  1445. mali_group_unlock(virtual_group);
  1446. mali_pp_scheduler_disable_group_internal(group);
  1447. } else {
  1448. mali_group_unlock(virtual_group);
  1449. break; /* No more physical groups in virtual group */
  1450. }
  1451. }
  1452. }
  1453. _mali_osk_pm_dev_ref_dec_no_power_on();
  1454. mali_pp_scheduler_resume();
  1455. }
  1456. int mali_pp_scheduler_set_perf_level(unsigned int target_core_nr, mali_bool override)
  1457. {
  1458. if (target_core_nr == enabled_cores) return 0;
  1459. if (MALI_FALSE == core_scaling_enabled && MALI_FALSE == override) return -EPERM;
  1460. if (target_core_nr > num_cores) return -EINVAL;
  1461. if (0 == target_core_nr) return -EINVAL;
  1462. if (target_core_nr > enabled_cores) {
  1463. mali_pp_scheduler_core_scale_up(target_core_nr);
  1464. } else if (target_core_nr < enabled_cores) {
  1465. mali_pp_scheduler_core_scale_down(target_core_nr);
  1466. }
  1467. if (target_core_nr != enabled_cores) {
  1468. MALI_DEBUG_PRINT(2, ("Core scaling failed, target number: %d, actual number: %d\n", target_core_nr, enabled_cores));
  1469. }
  1470. mali_pp_scheduler_notify_core_change(enabled_cores);
  1471. return 0;
  1472. }
  1473. void mali_pp_scheduler_core_scaling_enable(void)
  1474. {
  1475. /* PS: Core scaling is by default enabled */
  1476. core_scaling_enabled = MALI_TRUE;
  1477. }
  1478. void mali_pp_scheduler_core_scaling_disable(void)
  1479. {
  1480. core_scaling_enabled = MALI_FALSE;
  1481. }
  1482. mali_bool mali_pp_scheduler_core_scaling_is_enabled(void)
  1483. {
  1484. return core_scaling_enabled;
  1485. }
  1486. static void mali_pp_scheduler_job_queued(void)
  1487. {
  1488. /* We hold a PM reference for every job we hold queued (and running) */
  1489. _mali_osk_pm_dev_ref_add();
  1490. if (mali_utilization_enabled()) {
  1491. /*
  1492. * We cheat a little bit by counting the PP as busy from the time a PP job is queued.
  1493. * This will be fine because we only loose the tiny idle gap between jobs, but
  1494. * we will instead get less utilization work to do (less locks taken)
  1495. */
  1496. mali_utilization_pp_start();
  1497. }
  1498. }
  1499. static void mali_pp_scheduler_job_completed(void)
  1500. {
  1501. /* Release the PM reference we got in the mali_pp_scheduler_job_queued() function */
  1502. _mali_osk_pm_dev_ref_dec();
  1503. if (mali_utilization_enabled()) {
  1504. mali_utilization_pp_end();
  1505. }
  1506. }
  1507. static void mali_pp_scheduler_abort_job_and_unlock_scheduler(struct mali_pp_job *job)
  1508. {
  1509. MALI_DEBUG_ASSERT_POINTER(job);
  1510. MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
  1511. /* This job should not be on any lists. */
  1512. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
  1513. MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
  1514. _mali_osk_list_delinit(&job->session_fb_lookup_list);
  1515. mali_pp_scheduler_unlock();
  1516. /* Release tracker. */
  1517. mali_timeline_tracker_release(&job->tracker);
  1518. }
  1519. static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job)
  1520. {
  1521. _mali_osk_list_t *queue = NULL;
  1522. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  1523. struct mali_pp_job *iter, *tmp;
  1524. MALI_DEBUG_ASSERT_POINTER(job);
  1525. MALI_DEBUG_ASSERT_POINTER(job->session);
  1526. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  1527. if (mali_pp_job_needs_dma_buf_mapping(job)) {
  1528. mali_dma_buf_map_job(job);
  1529. }
  1530. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  1531. mali_pp_scheduler_lock();
  1532. if (unlikely(job->session->is_aborting)) {
  1533. /* Before checking if the session is aborting, the scheduler must be locked. */
  1534. MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
  1535. MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) queued while session is aborting.\n", mali_pp_job_get_id(job), job));
  1536. mali_pp_scheduler_abort_job_and_unlock_scheduler(job);
  1537. /* Delete job. */
  1538. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
  1539. mali_pp_scheduler_deferred_job_delete(job);
  1540. #else
  1541. mali_pp_job_delete(job);
  1542. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
  1543. mali_pp_scheduler_job_completed();
  1544. /* Since we are aborting we ignore the scheduler mask. */
  1545. return MALI_SCHEDULER_MASK_EMPTY;
  1546. }
  1547. #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
  1548. trace_gpu_job_enqueue(mali_pp_job_get_tid(job), mali_pp_job_get_id(job), "PP");
  1549. #endif
  1550. _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_PP_ENQUEUE, job->pid, job->tid, job->uargs.frame_builder_id, job->uargs.flush_id, 0);
  1551. job->cache_order = mali_scheduler_get_new_cache_order();
  1552. /* Determine which queue the job should be added to. */
  1553. if (mali_pp_job_is_virtual(job)) {
  1554. if (job->session->use_high_priority_job_queue) {
  1555. queue = &virtual_job_queue.high_pri;
  1556. } else {
  1557. queue = &virtual_job_queue.normal_pri;
  1558. }
  1559. virtual_job_queue.depth += 1;
  1560. /* Set schedule bitmask if the virtual group is idle. */
  1561. if (VIRTUAL_GROUP_IDLE == virtual_group_state) {
  1562. schedule_mask |= MALI_SCHEDULER_MASK_PP;
  1563. }
  1564. } else {
  1565. if (job->session->use_high_priority_job_queue) {
  1566. queue = &job_queue.high_pri;
  1567. } else {
  1568. queue = &job_queue.normal_pri;
  1569. }
  1570. job_queue.depth += mali_pp_job_get_sub_job_count(job);
  1571. /* Set schedule bitmask if there are physical PP cores available, or if there is an
  1572. * idle virtual group. */
  1573. if (!_mali_osk_list_empty(&group_list_idle)
  1574. || (mali_pp_scheduler_has_virtual_group()
  1575. && (VIRTUAL_GROUP_IDLE == virtual_group_state))) {
  1576. schedule_mask |= MALI_SCHEDULER_MASK_PP;
  1577. }
  1578. }
  1579. /* Find position in queue where job should be added. */
  1580. _MALI_OSK_LIST_FOREACHENTRY_REVERSE(iter, tmp, queue, struct mali_pp_job, list) {
  1581. if (mali_pp_job_should_start_after(job, iter)) {
  1582. break;
  1583. }
  1584. }
  1585. /* Add job to queue. */
  1586. _mali_osk_list_add(&job->list, &iter->list);
  1587. /* Add job to session list. */
  1588. _mali_osk_list_addtail(&job->session_list, &(job->session->pp_job_list));
  1589. MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) with %u parts queued.\n",
  1590. mali_pp_job_is_virtual(job) ? "Virtual" : "Physical",
  1591. mali_pp_job_get_id(job), job, mali_pp_job_get_sub_job_count(job)));
  1592. mali_pp_scheduler_unlock();
  1593. return schedule_mask;
  1594. }
  1595. mali_scheduler_mask mali_pp_scheduler_activate_job(struct mali_pp_job *job)
  1596. {
  1597. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  1598. MALI_DEBUG_ASSERT_POINTER(job);
  1599. MALI_DEBUG_ASSERT_POINTER(job->session);
  1600. MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Timeline activation for job %u (0x%08X).\n", mali_pp_job_get_id(job), job));
  1601. if (MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT & job->tracker.activation_error) {
  1602. MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) activated with error, aborting.\n", mali_pp_job_get_id(job), job));
  1603. mali_pp_scheduler_lock();
  1604. mali_pp_scheduler_abort_job_and_unlock_scheduler(job);
  1605. mali_pp_job_mark_sub_job_completed(job, MALI_FALSE); /* Flagging the job as failed. */
  1606. mali_pp_scheduler_finalize_job(job);
  1607. return MALI_SCHEDULER_MASK_EMPTY;
  1608. }
  1609. /* PP job is ready to run, queue it. */
  1610. #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
  1611. if (mali_pp_job_needs_dma_buf_mapping(job)) {
  1612. mali_pp_scheduler_deferred_job_queue(job);
  1613. return MALI_SCHEDULER_MASK_EMPTY;
  1614. }
  1615. #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
  1616. schedule_mask = mali_pp_scheduler_queue_job(job);
  1617. return schedule_mask;
  1618. }