mali_soft_job.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * This confidential and proprietary software may be used only as
  3. * authorised by a licensing agreement from ARM Limited
  4. * (C) COPYRIGHT 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_soft_job.h"
  11. #include "mali_osk.h"
  12. #include "mali_osk_mali.h"
  13. #include "mali_timeline.h"
  14. #include "mali_session.h"
  15. #include "mali_kernel_common.h"
  16. #include "mali_uk_types.h"
  17. #include "mali_scheduler.h"
  18. MALI_STATIC_INLINE void mali_soft_job_system_lock(struct mali_soft_job_system *system)
  19. {
  20. MALI_DEBUG_ASSERT_POINTER(system);
  21. _mali_osk_spinlock_irq_lock(system->lock);
  22. MALI_DEBUG_PRINT(5, ("Mali Soft Job: soft system %p lock taken\n", system));
  23. MALI_DEBUG_ASSERT(0 == system->lock_owner);
  24. MALI_DEBUG_CODE(system->lock_owner = _mali_osk_get_tid());
  25. }
  26. MALI_STATIC_INLINE void mali_soft_job_system_unlock(struct mali_soft_job_system *system)
  27. {
  28. MALI_DEBUG_ASSERT_POINTER(system);
  29. MALI_DEBUG_PRINT(5, ("Mali Soft Job: releasing soft system %p lock\n", system));
  30. MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner);
  31. MALI_DEBUG_CODE(system->lock_owner = 0);
  32. _mali_osk_spinlock_irq_unlock(system->lock);
  33. }
  34. #if defined(DEBUG)
  35. MALI_STATIC_INLINE void mali_soft_job_system_assert_locked(struct mali_soft_job_system *system)
  36. {
  37. MALI_DEBUG_ASSERT_POINTER(system);
  38. MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner);
  39. }
  40. #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system) mali_soft_job_system_assert_locked(system)
  41. #else
  42. #define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system)
  43. #endif /* defined(DEBUG) */
  44. struct mali_soft_job_system *mali_soft_job_system_create(struct mali_session_data *session)
  45. {
  46. u32 i;
  47. struct mali_soft_job_system *system;
  48. struct mali_soft_job *job;
  49. MALI_DEBUG_ASSERT_POINTER(session);
  50. system = (struct mali_soft_job_system *) _mali_osk_calloc(1, sizeof(struct mali_soft_job_system));
  51. if (NULL == system) {
  52. return NULL;
  53. }
  54. system->session = session;
  55. system->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  56. if (NULL == system->lock) {
  57. mali_soft_job_system_destroy(system);
  58. return NULL;
  59. }
  60. system->lock_owner = 0;
  61. _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_free));
  62. _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_used));
  63. for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) {
  64. job = &(system->jobs[i]);
  65. _mali_osk_list_add(&(job->system_list), &(system->jobs_free));
  66. job->system = system;
  67. job->state = MALI_SOFT_JOB_STATE_FREE;
  68. job->id = i;
  69. }
  70. return system;
  71. }
  72. void mali_soft_job_system_destroy(struct mali_soft_job_system *system)
  73. {
  74. MALI_DEBUG_ASSERT_POINTER(system);
  75. /* All jobs should be free at this point. */
  76. MALI_DEBUG_CODE( {
  77. u32 i;
  78. struct mali_soft_job *job;
  79. for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i)
  80. {
  81. job = &(system->jobs[i]);
  82. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state);
  83. }
  84. });
  85. if (NULL != system) {
  86. if (NULL != system->lock) {
  87. _mali_osk_spinlock_irq_term(system->lock);
  88. }
  89. _mali_osk_free(system);
  90. }
  91. }
  92. static struct mali_soft_job *mali_soft_job_system_alloc_job(struct mali_soft_job_system *system)
  93. {
  94. struct mali_soft_job *job;
  95. MALI_DEBUG_ASSERT_POINTER(system);
  96. MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
  97. if (_mali_osk_list_empty(&(system->jobs_free))) {
  98. /* No jobs available. */
  99. return NULL;
  100. }
  101. /* Grab first job and move it to the used list. */
  102. job = _MALI_OSK_LIST_ENTRY(system->jobs_free.next, struct mali_soft_job, system_list);
  103. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state);
  104. _mali_osk_list_move(&(job->system_list), &(system->jobs_used));
  105. job->state = MALI_SOFT_JOB_STATE_ALLOCATED;
  106. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
  107. MALI_DEBUG_ASSERT(system == job->system);
  108. return job;
  109. }
  110. static void mali_soft_job_system_free_job(struct mali_soft_job_system *system, struct mali_soft_job *job)
  111. {
  112. MALI_DEBUG_ASSERT_POINTER(job);
  113. MALI_DEBUG_ASSERT_POINTER(system);
  114. mali_soft_job_system_lock(job->system);
  115. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE != job->state);
  116. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
  117. MALI_DEBUG_ASSERT(system == job->system);
  118. job->state = MALI_SOFT_JOB_STATE_FREE;
  119. _mali_osk_list_move(&(job->system_list), &(system->jobs_free));
  120. mali_soft_job_system_unlock(job->system);
  121. }
  122. MALI_STATIC_INLINE struct mali_soft_job *mali_soft_job_system_lookup_job(struct mali_soft_job_system *system, u32 job_id)
  123. {
  124. MALI_DEBUG_ASSERT_POINTER(system);
  125. MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system);
  126. if (job_id < MALI_MAX_NUM_SOFT_JOBS) {
  127. return &system->jobs[job_id];
  128. }
  129. return NULL;
  130. }
  131. void mali_soft_job_destroy(struct mali_soft_job *job)
  132. {
  133. MALI_DEBUG_ASSERT_POINTER(job);
  134. MALI_DEBUG_ASSERT_POINTER(job->system);
  135. MALI_DEBUG_PRINT(4, ("Mali Soft Job: destroying soft job %u (0x%08X)\n", job->id, job));
  136. if (NULL != job) {
  137. if (0 < _mali_osk_atomic_dec_return(&job->refcount)) return;
  138. _mali_osk_atomic_term(&job->refcount);
  139. if (NULL != job->activated_notification) {
  140. _mali_osk_notification_delete(job->activated_notification);
  141. job->activated_notification = NULL;
  142. }
  143. mali_soft_job_system_free_job(job->system, job);
  144. }
  145. }
  146. struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u32 user_job)
  147. {
  148. struct mali_soft_job *job;
  149. _mali_osk_notification_t *notification = NULL;
  150. MALI_DEBUG_ASSERT_POINTER(system);
  151. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_TYPE_USER_SIGNALED >= type);
  152. if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) {
  153. notification = _mali_osk_notification_create(_MALI_NOTIFICATION_SOFT_ACTIVATED, sizeof(_mali_uk_soft_job_activated_s));
  154. if (unlikely(NULL == notification)) {
  155. MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate notification"));
  156. return NULL;
  157. }
  158. }
  159. mali_soft_job_system_lock(system);
  160. job = mali_soft_job_system_alloc_job(system);
  161. if (NULL == job) {
  162. mali_soft_job_system_unlock(system);
  163. MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate job"));
  164. _mali_osk_notification_delete(notification);
  165. return NULL;
  166. }
  167. job->type = type;
  168. job->user_job = user_job;
  169. job->activated = MALI_FALSE;
  170. if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) {
  171. job->activated_notification = notification;
  172. }
  173. _mali_osk_atomic_init(&job->refcount, 1);
  174. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
  175. MALI_DEBUG_ASSERT(system == job->system);
  176. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id);
  177. mali_soft_job_system_unlock(system);
  178. return job;
  179. }
  180. mali_timeline_point mali_soft_job_start(struct mali_soft_job *job, struct mali_timeline_fence *fence)
  181. {
  182. mali_timeline_point point;
  183. struct mali_soft_job_system *system;
  184. MALI_DEBUG_ASSERT_POINTER(job);
  185. MALI_DEBUG_ASSERT_POINTER(fence);
  186. MALI_DEBUG_ASSERT_POINTER(job->system);
  187. system = job->system;
  188. MALI_DEBUG_ASSERT_POINTER(system->session);
  189. MALI_DEBUG_ASSERT_POINTER(system->session->timeline_system);
  190. mali_soft_job_system_lock(system);
  191. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state);
  192. job->state = MALI_SOFT_JOB_STATE_STARTED;
  193. mali_soft_job_system_unlock(system);
  194. MALI_DEBUG_PRINT(4, ("Mali Soft Job: starting soft job %u (0x%08X)\n", job->id, job));
  195. mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_SOFT, fence, job);
  196. point = mali_timeline_system_add_tracker(system->session->timeline_system, &job->tracker, MALI_TIMELINE_SOFT);
  197. return point;
  198. }
  199. static mali_bool mali_soft_job_is_activated(void *data)
  200. {
  201. struct mali_soft_job *job;
  202. job = (struct mali_soft_job *) data;
  203. MALI_DEBUG_ASSERT_POINTER(job);
  204. return job->activated;
  205. }
  206. _mali_osk_errcode_t mali_soft_job_system_signal_job(struct mali_soft_job_system *system, u32 job_id)
  207. {
  208. struct mali_soft_job *job;
  209. struct mali_timeline_system *timeline_system;
  210. mali_scheduler_mask schedule_mask;
  211. MALI_DEBUG_ASSERT_POINTER(system);
  212. mali_soft_job_system_lock(system);
  213. job = mali_soft_job_system_lookup_job(system, job_id);
  214. if (NULL == job || !(MALI_SOFT_JOB_STATE_STARTED == job->state || MALI_SOFT_JOB_STATE_TIMED_OUT == job->state)) {
  215. mali_soft_job_system_unlock(system);
  216. MALI_PRINT_ERROR(("Mali Soft Job: invalid soft job id %u", job_id));
  217. return _MALI_OSK_ERR_ITEM_NOT_FOUND;
  218. }
  219. if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) {
  220. job->state = MALI_SOFT_JOB_STATE_SIGNALED;
  221. mali_soft_job_system_unlock(system);
  222. MALI_DEBUG_ASSERT(MALI_TRUE == job->activated);
  223. MALI_DEBUG_PRINT(4, ("Mali Soft Job: soft job %u (0x%08X) was timed out\n", job->id, job));
  224. mali_soft_job_destroy(job);
  225. return _MALI_OSK_ERR_TIMEOUT;
  226. }
  227. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
  228. job->state = MALI_SOFT_JOB_STATE_SIGNALED;
  229. mali_soft_job_system_unlock(system);
  230. /* Since the job now is in signaled state, timeouts from the timeline system will be
  231. * ignored, and it is not possible to signal this job again. */
  232. timeline_system = system->session->timeline_system;
  233. MALI_DEBUG_ASSERT_POINTER(timeline_system);
  234. /* Wait until activated. */
  235. _mali_osk_wait_queue_wait_event(timeline_system->wait_queue, mali_soft_job_is_activated, (void *) job);
  236. MALI_DEBUG_PRINT(4, ("Mali Soft Job: signaling soft job %u (0x%08X)\n", job->id, job));
  237. schedule_mask = mali_timeline_tracker_release(&job->tracker);
  238. mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
  239. mali_soft_job_destroy(job);
  240. return _MALI_OSK_ERR_OK;
  241. }
  242. static void mali_soft_job_send_activated_notification(struct mali_soft_job *job)
  243. {
  244. if (NULL != job->activated_notification) {
  245. _mali_uk_soft_job_activated_s *res = job->activated_notification->result_buffer;
  246. res->user_job = job->user_job;
  247. mali_session_send_notification(job->system->session, job->activated_notification);
  248. }
  249. job->activated_notification = NULL;
  250. }
  251. void mali_soft_job_system_activate_job(struct mali_soft_job *job)
  252. {
  253. MALI_DEBUG_ASSERT_POINTER(job);
  254. MALI_DEBUG_ASSERT_POINTER(job->system);
  255. MALI_DEBUG_ASSERT_POINTER(job->system->session);
  256. MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline activation for soft job %u (0x%08X).\n", job->id, job));
  257. mali_soft_job_system_lock(job->system);
  258. if (unlikely(job->system->session->is_aborting)) {
  259. MALI_DEBUG_PRINT(3, ("Mali Soft Job: Soft job %u (0x%08X) activated while session is aborting.\n", job->id, job));
  260. mali_soft_job_system_unlock(job->system);
  261. /* Since we are in shutdown, we can ignore the scheduling bitmask. */
  262. mali_timeline_tracker_release(&job->tracker);
  263. mali_soft_job_destroy(job);
  264. return;
  265. }
  266. /* Send activated notification. */
  267. mali_soft_job_send_activated_notification(job);
  268. /* Wake up sleeping signaler. */
  269. job->activated = MALI_TRUE;
  270. _mali_osk_wait_queue_wake_up(job->tracker.system->wait_queue);
  271. mali_soft_job_system_unlock(job->system);
  272. }
  273. mali_scheduler_mask mali_soft_job_system_timeout_job(struct mali_soft_job *job)
  274. {
  275. mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
  276. MALI_DEBUG_ASSERT_POINTER(job);
  277. MALI_DEBUG_ASSERT_POINTER(job->system);
  278. MALI_DEBUG_ASSERT_POINTER(job->system->session);
  279. MALI_DEBUG_ASSERT(MALI_TRUE == job->activated);
  280. MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline timeout for soft job %u (0x%08X).\n", job->id, job));
  281. mali_soft_job_system_lock(job->system);
  282. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state ||
  283. MALI_SOFT_JOB_STATE_SIGNALED == job->state);
  284. if (unlikely(job->system->session->is_aborting)) {
  285. /* The session is aborting. This job will be released and destroyed by @ref
  286. * mali_soft_job_system_abort(). */
  287. mali_soft_job_system_unlock(job->system);
  288. return MALI_SCHEDULER_MASK_EMPTY;
  289. }
  290. if (MALI_SOFT_JOB_STATE_STARTED != job->state) {
  291. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state);
  292. /* The job is about to be signaled, ignore timeout. */
  293. MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeout on soft job %u (0x%08X) in signaled state.\n", job->id, job));
  294. mali_soft_job_system_unlock(job->system);
  295. return schedule_mask;
  296. }
  297. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state);
  298. job->state = MALI_SOFT_JOB_STATE_TIMED_OUT;
  299. _mali_osk_atomic_inc(&job->refcount);
  300. mali_soft_job_system_unlock(job->system);
  301. schedule_mask = mali_timeline_tracker_release(&job->tracker);
  302. mali_soft_job_destroy(job);
  303. return schedule_mask;
  304. }
  305. void mali_soft_job_system_abort(struct mali_soft_job_system *system)
  306. {
  307. u32 i;
  308. struct mali_soft_job *job, *tmp;
  309. _MALI_OSK_LIST_HEAD_STATIC_INIT(jobs);
  310. MALI_DEBUG_ASSERT_POINTER(system);
  311. MALI_DEBUG_ASSERT_POINTER(system->session);
  312. MALI_DEBUG_ASSERT(system->session->is_aborting);
  313. MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting soft job system for session 0x%08X.\n", system->session));
  314. mali_soft_job_system_lock(system);
  315. for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) {
  316. job = &(system->jobs[i]);
  317. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state ||
  318. MALI_SOFT_JOB_STATE_STARTED == job->state ||
  319. MALI_SOFT_JOB_STATE_TIMED_OUT == job->state);
  320. if (MALI_SOFT_JOB_STATE_STARTED == job->state) {
  321. /* If the job has been activated, we have to release the tracker and destroy
  322. * the job. If not, the tracker will be released and the job destroyed when
  323. * it is activated. */
  324. if (MALI_TRUE == job->activated) {
  325. MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting unsignaled soft job %u (0x%08X).\n", job->id, job));
  326. job->state = MALI_SOFT_JOB_STATE_SIGNALED;
  327. _mali_osk_list_move(&job->system_list, &jobs);
  328. }
  329. } else if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) {
  330. MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting timed out soft job %u (0x%08X).\n", job->id, job));
  331. /* We need to destroy this soft job. */
  332. _mali_osk_list_move(&job->system_list, &jobs);
  333. }
  334. }
  335. mali_soft_job_system_unlock(system);
  336. /* Release and destroy jobs. */
  337. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &jobs, struct mali_soft_job, system_list) {
  338. MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state ||
  339. MALI_SOFT_JOB_STATE_TIMED_OUT == job->state);
  340. if (MALI_SOFT_JOB_STATE_SIGNALED == job->state) {
  341. mali_timeline_tracker_release(&job->tracker);
  342. }
  343. /* Move job back to used list before destroying. */
  344. _mali_osk_list_move(&job->system_list, &system->jobs_used);
  345. mali_soft_job_destroy(job);
  346. }
  347. }