PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c

https://bitbucket.org/thenameisnigel/android_kernel_samsung_smdk4210
C | 443 lines | 321 code | 88 blank | 34 comment | 46 complexity | ea7e33108ccf1d130127607d378591fb MD5 | raw file
  1. /*
  2. * Copyright (C) 2012 ARM Limited. All rights reserved.
  3. *
  4. * This program is free software and is provided to you under the terms of the GNU General Public License version 2
  5. * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
  6. *
  7. * A copy of the licence is included with the program, and can also be obtained from Free Software
  8. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  9. */
  10. #include "mali_gp_scheduler.h"
  11. #include "mali_kernel_common.h"
  12. #include "mali_osk.h"
  13. #include "mali_osk_list.h"
  14. #include "mali_scheduler.h"
  15. #include "mali_gp.h"
  16. #include "mali_gp_job.h"
  17. #include "mali_group.h"
  18. #include "mali_cluster.h"
  19. enum mali_gp_slot_state
  20. {
  21. MALI_GP_SLOT_STATE_IDLE,
  22. MALI_GP_SLOT_STATE_WORKING,
  23. };
  24. /* A render slot is an entity which jobs can be scheduled onto */
  25. struct mali_gp_slot
  26. {
  27. struct mali_group *group;
  28. /*
  29. * We keep track of the state here as well as in the group object
  30. * so we don't need to take the group lock so often (and also avoid clutter with the working lock)
  31. */
  32. enum mali_gp_slot_state state;
  33. u32 returned_cookie;
  34. };
  35. static u32 gp_version = 0;
  36. static _MALI_OSK_LIST_HEAD(job_queue); /* List of jobs with some unscheduled work */
  37. static struct mali_gp_slot slot;
  38. /* Variables to allow safe pausing of the scheduler */
  39. static _mali_osk_wait_queue_t *gp_scheduler_working_wait_queue = NULL;
  40. static u32 pause_count = 0;
  41. static mali_bool mali_gp_scheduler_is_suspended(void);
  42. static _mali_osk_lock_t *gp_scheduler_lock = NULL;
  43. /* Contains tid of thread that locked the scheduler or 0, if not locked */
  44. _mali_osk_errcode_t mali_gp_scheduler_initialize(void)
  45. {
  46. u32 i;
  47. _MALI_OSK_INIT_LIST_HEAD(&job_queue);
  48. gp_scheduler_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_SCHEDULER);
  49. if (NULL == gp_scheduler_lock)
  50. {
  51. return _MALI_OSK_ERR_NOMEM;
  52. }
  53. gp_scheduler_working_wait_queue = _mali_osk_wait_queue_init();
  54. if (NULL == gp_scheduler_working_wait_queue)
  55. {
  56. _mali_osk_lock_term(gp_scheduler_lock);
  57. return _MALI_OSK_ERR_NOMEM;
  58. }
  59. /* Find all the available GP cores */
  60. for (i = 0; i < mali_cluster_get_glob_num_clusters(); i++)
  61. {
  62. u32 group_id = 0;
  63. struct mali_cluster *curr_cluster = mali_cluster_get_global_cluster(i);
  64. struct mali_group *group = mali_cluster_get_group(curr_cluster, group_id);
  65. while (NULL != group)
  66. {
  67. struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
  68. if (NULL != gp_core)
  69. {
  70. if (0 == gp_version)
  71. {
  72. /* Retrieve GP version */
  73. gp_version = mali_gp_core_get_version(gp_core);
  74. }
  75. slot.group = group;
  76. slot.state = MALI_GP_SLOT_STATE_IDLE;
  77. break; /* There are only one GP, no point in looking for more */
  78. }
  79. group_id++;
  80. group = mali_cluster_get_group(curr_cluster, group_id);
  81. }
  82. }
  83. return _MALI_OSK_ERR_OK;
  84. }
  85. void mali_gp_scheduler_terminate(void)
  86. {
  87. _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue);
  88. _mali_osk_lock_term(gp_scheduler_lock);
  89. }
  90. MALI_STATIC_INLINE void mali_gp_scheduler_lock(void)
  91. {
  92. if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW))
  93. {
  94. /* Non-interruptable lock failed: this should never happen. */
  95. MALI_DEBUG_ASSERT(0);
  96. }
  97. MALI_DEBUG_PRINT(5, ("Mali GP scheduler: GP scheduler lock taken\n"));
  98. }
  99. MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void)
  100. {
  101. MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n"));
  102. _mali_osk_lock_signal(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW);
  103. }
  104. #ifdef DEBUG
  105. MALI_STATIC_INLINE void mali_gp_scheduler_assert_locked(void)
  106. {
  107. MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock);
  108. }
  109. #define MALI_ASSERT_GP_SCHEDULER_LOCKED() mali_gp_scheduler_assert_locked()
  110. #else
  111. #define MALI_ASSERT_GP_SCHEDULER_LOCKED()
  112. #endif
  113. static void mali_gp_scheduler_schedule(void)
  114. {
  115. struct mali_gp_job *job;
  116. MALI_ASSERT_GP_SCHEDULER_LOCKED();
  117. if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state || _mali_osk_list_empty(&job_queue))
  118. {
  119. MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n",
  120. pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0));
  121. return; /* Nothing to do, so early out */
  122. }
  123. job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_gp_job, list);
  124. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Starting job %u (0x%08X)\n", mali_gp_job_get_id(job), job));
  125. if (_MALI_OSK_ERR_OK == mali_group_start_gp_job(slot.group, job))
  126. {
  127. /* Mark slot as busy */
  128. slot.state = MALI_GP_SLOT_STATE_WORKING;
  129. /* Remove from queue of unscheduled jobs */
  130. _mali_osk_list_del(&job->list);
  131. }
  132. else
  133. {
  134. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Failed to start GP job\n"));
  135. }
  136. }
  137. static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success)
  138. {
  139. _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s));
  140. if (NULL != notobj)
  141. {
  142. _mali_uk_gp_job_finished_s *jobres = notobj->result_buffer;
  143. _mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
  144. jobres->user_job_ptr = mali_gp_job_get_user_id(job);
  145. if (MALI_TRUE == success)
  146. {
  147. jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
  148. }
  149. else
  150. {
  151. jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
  152. }
  153. jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job);
  154. jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job);
  155. jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job);
  156. mali_session_send_notification(mali_gp_job_get_session(job), notobj);
  157. }
  158. else
  159. {
  160. MALI_PRINT_ERROR(("Mali GP scheduler: Unable to allocate notification object\n"));
  161. }
  162. mali_gp_job_delete(job);
  163. }
  164. void mali_gp_scheduler_do_schedule(void)
  165. {
  166. mali_gp_scheduler_lock();
  167. mali_gp_scheduler_schedule();
  168. mali_gp_scheduler_unlock();
  169. }
  170. void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success)
  171. {
  172. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) completed (%s)\n", mali_gp_job_get_id(job), job, success ? "success" : "failure"));
  173. mali_gp_scheduler_lock();
  174. /* Mark slot as idle again */
  175. slot.state = MALI_GP_SLOT_STATE_IDLE;
  176. /* If paused, then this was the last job, so wake up sleeping workers */
  177. if (pause_count > 0)
  178. {
  179. _mali_osk_wait_queue_wake_up(gp_scheduler_working_wait_queue);
  180. }
  181. else
  182. {
  183. mali_gp_scheduler_schedule();
  184. }
  185. mali_gp_scheduler_unlock();
  186. mali_gp_scheduler_return_job_to_user(job, success);
  187. }
  188. void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job)
  189. {
  190. _mali_osk_notification_t *notobj;
  191. notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s));
  192. if (NULL != notobj)
  193. {
  194. _mali_uk_gp_job_suspended_s * jobres;
  195. mali_gp_scheduler_lock();
  196. jobres = (_mali_uk_gp_job_suspended_s *)notobj->result_buffer;
  197. jobres->user_job_ptr = mali_gp_job_get_user_id(job);
  198. jobres->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY;
  199. jobres->cookie = mali_gp_job_get_id(job);
  200. slot.returned_cookie = jobres->cookie;
  201. mali_session_send_notification(mali_gp_job_get_session(job), notobj);
  202. mali_gp_scheduler_unlock();
  203. }
  204. /*
  205. * If this function failed, then we could return the job to user space right away,
  206. * but there is a job timer anyway that will do that eventually.
  207. * This is not exactly a common case anyway.
  208. */
  209. }
  210. void mali_gp_scheduler_suspend(void)
  211. {
  212. mali_gp_scheduler_lock();
  213. pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */
  214. mali_gp_scheduler_unlock();
  215. _mali_osk_wait_queue_wait_event(gp_scheduler_working_wait_queue, mali_gp_scheduler_is_suspended);
  216. }
  217. void mali_gp_scheduler_resume(void)
  218. {
  219. mali_gp_scheduler_lock();
  220. pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */
  221. if (0 == pause_count)
  222. {
  223. mali_gp_scheduler_schedule();
  224. }
  225. mali_gp_scheduler_unlock();
  226. }
  227. _mali_osk_errcode_t _mali_ukk_gp_start_job(_mali_uk_gp_start_job_s *args)
  228. {
  229. struct mali_session_data *session;
  230. struct mali_gp_job *job;
  231. MALI_DEBUG_ASSERT_POINTER(args);
  232. if (NULL == args->ctx)
  233. {
  234. return _MALI_OSK_ERR_INVALID_ARGS;
  235. }
  236. session = (struct mali_session_data*)args->ctx;
  237. if (NULL == session)
  238. {
  239. return _MALI_OSK_ERR_FAULT;
  240. }
  241. job = mali_gp_job_create(session, args, mali_scheduler_get_new_id());
  242. if (NULL == job)
  243. {
  244. return _MALI_OSK_ERR_NOMEM;
  245. }
  246. #if PROFILING_SKIP_PP_AND_GP_JOBS
  247. #warning GP jobs will not be executed
  248. mali_gp_scheduler_return_job_to_user(job, MALI_TRUE);
  249. return _MALI_OSK_ERR_OK;
  250. #endif
  251. mali_gp_scheduler_lock();
  252. _mali_osk_list_addtail(&job->list, &job_queue);
  253. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n", mali_gp_job_get_id(job), job));
  254. mali_gp_scheduler_schedule();
  255. mali_gp_scheduler_unlock();
  256. return _MALI_OSK_ERR_OK;
  257. }
  258. _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args)
  259. {
  260. MALI_DEBUG_ASSERT_POINTER(args);
  261. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  262. args->number_of_cores = 1;
  263. return _MALI_OSK_ERR_OK;
  264. }
  265. _mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args)
  266. {
  267. MALI_DEBUG_ASSERT_POINTER(args);
  268. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  269. args->version = gp_version;
  270. return _MALI_OSK_ERR_OK;
  271. }
  272. _mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args)
  273. {
  274. struct mali_session_data *session;
  275. _mali_osk_errcode_t ret = _MALI_OSK_ERR_FAULT;
  276. MALI_DEBUG_ASSERT_POINTER(args);
  277. if (NULL == args->ctx)
  278. {
  279. return _MALI_OSK_ERR_INVALID_ARGS;
  280. }
  281. session = (struct mali_session_data*)args->ctx;
  282. if (NULL == session)
  283. {
  284. return _MALI_OSK_ERR_FAULT;
  285. }
  286. mali_gp_scheduler_lock();
  287. /* Make sure that the cookie returned by user space is the same as we provided in the first place */
  288. if (args->cookie != slot.returned_cookie)
  289. {
  290. MALI_DEBUG_PRINT(2, ("Mali GP scheduler: Got an illegal cookie from user space, expected %u but got %u (job id)\n", slot.returned_cookie, args->cookie)) ;
  291. mali_gp_scheduler_unlock();
  292. return _MALI_OSK_ERR_FAULT;
  293. }
  294. mali_gp_scheduler_unlock();
  295. switch (args->code)
  296. {
  297. case _MALIGP_JOB_RESUME_WITH_NEW_HEAP:
  298. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1]));
  299. mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]);
  300. ret = _MALI_OSK_ERR_OK;
  301. break;
  302. case _MALIGP_JOB_ABORT:
  303. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie));
  304. mali_group_abort_gp_job(slot.group, args->cookie);
  305. ret = _MALI_OSK_ERR_OK;
  306. break;
  307. default:
  308. MALI_PRINT_ERROR(("Mali GP scheduler: Wrong suspend response from user space\n"));
  309. ret = _MALI_OSK_ERR_FAULT;
  310. break;
  311. }
  312. return ret;
  313. }
  314. void mali_gp_scheduler_abort_session(struct mali_session_data *session)
  315. {
  316. struct mali_gp_job *job, *tmp;
  317. mali_gp_scheduler_lock();
  318. MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting all jobs from session 0x%08x\n", session));
  319. /* Check queue for jobs and remove */
  320. _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_gp_job, list)
  321. {
  322. if (mali_gp_job_get_session(job) == session)
  323. {
  324. MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Removing GP job 0x%08x from queue\n", job));
  325. _mali_osk_list_del(&(job->list));
  326. mali_gp_job_delete(job);
  327. }
  328. }
  329. mali_gp_scheduler_unlock();
  330. /* Abort running jobs from this session. It is safe to do this outside
  331. * the scheduler lock as there is only one GP core, and the queue has
  332. * already been emptied, as long as there are no new jobs coming in
  333. * from user space. */
  334. mali_group_abort_session(slot.group, session);
  335. }
  336. static mali_bool mali_gp_scheduler_is_suspended(void)
  337. {
  338. mali_bool ret;
  339. mali_gp_scheduler_lock();
  340. ret = pause_count > 0 && slot.state == MALI_GP_SLOT_STATE_IDLE;
  341. mali_gp_scheduler_unlock();
  342. return ret;
  343. }
  344. #if MALI_STATE_TRACKING
  345. u32 mali_gp_scheduler_dump_state(char *buf, u32 size)
  346. {
  347. int n = 0;
  348. n += _mali_osk_snprintf(buf + n, size - n, "GP\n");
  349. n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty");
  350. n += mali_group_dump_state(slot.group, buf + n, size - n);
  351. n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", mali_group_gp_state(slot.group));
  352. n += _mali_osk_snprintf(buf + n, size - n, "\n");
  353. return n;
  354. }
  355. #endif