sched_entity.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*
  2. * Copyright 2015 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. */
  23. #include <linux/kthread.h>
  24. #include <linux/slab.h>
  25. #include <linux/completion.h>
  26. #include <drm/drm_print.h>
  27. #include <drm/gpu_scheduler.h>
  28. #include "gpu_scheduler_trace.h"
  29. #define to_drm_sched_job(sched_job) \
  30. container_of((sched_job), struct drm_sched_job, queue_node)
  31. /**
  32. * drm_sched_entity_init - Init a context entity used by scheduler when
  33. * submit to HW ring.
  34. *
  35. * @entity: scheduler entity to init
  36. * @priority: priority of the entity
  37. * @sched_list: the list of drm scheds on which jobs from this
  38. * entity can be submitted
  39. * @num_sched_list: number of drm sched in sched_list
  40. * @guilty: atomic_t set to 1 when a job on this queue
  41. * is found to be guilty causing a timeout
  42. *
  43. * Note that the &sched_list must have at least one element to schedule the entity.
  44. *
  45. * For changing @priority later on at runtime see
  46. * drm_sched_entity_set_priority(). For changing the set of schedulers
  47. * @sched_list at runtime see drm_sched_entity_modify_sched().
  48. *
  49. * An entity is cleaned up by callind drm_sched_entity_fini(). See also
  50. * drm_sched_entity_destroy().
  51. *
  52. * Returns 0 on success or a negative error code on failure.
  53. */
  54. int drm_sched_entity_init(struct drm_sched_entity *entity,
  55. enum drm_sched_priority priority,
  56. struct drm_gpu_scheduler **sched_list,
  57. unsigned int num_sched_list,
  58. atomic_t *guilty)
  59. {
  60. if (!(entity && sched_list && (num_sched_list == 0 || sched_list[0])))
  61. return -EINVAL;
  62. memset(entity, 0, sizeof(struct drm_sched_entity));
  63. INIT_LIST_HEAD(&entity->list);
  64. entity->rq = NULL;
  65. entity->guilty = guilty;
  66. entity->num_sched_list = num_sched_list;
  67. entity->priority = priority;
  68. /*
  69. * It's perfectly valid to initialize an entity without having a valid
  70. * scheduler attached. It's just not valid to use the scheduler before it
  71. * is initialized itself.
  72. */
  73. entity->sched_list = num_sched_list > 1 ? sched_list : NULL;
  74. RCU_INIT_POINTER(entity->last_scheduled, NULL);
  75. RB_CLEAR_NODE(&entity->rb_tree_node);
  76. if (num_sched_list && !sched_list[0]->sched_rq) {
  77. /* Since every entry covered by num_sched_list
  78. * should be non-NULL and therefore we warn drivers
  79. * not to do this and to fix their DRM calling order.
  80. */
  81. pr_warn("%s: called with uninitialized scheduler\n", __func__);
  82. } else if (num_sched_list) {
  83. /* The "priority" of an entity cannot exceed the number of run-queues of a
  84. * scheduler. Protect against num_rqs being 0, by converting to signed. Choose
  85. * the lowest priority available.
  86. */
  87. if (entity->priority >= sched_list[0]->num_rqs) {
  88. drm_err(sched_list[0], "entity with out-of-bounds priority:%u num_rqs:%u\n",
  89. entity->priority, sched_list[0]->num_rqs);
  90. entity->priority = max_t(s32, (s32) sched_list[0]->num_rqs - 1,
  91. (s32) DRM_SCHED_PRIORITY_KERNEL);
  92. }
  93. entity->rq = sched_list[0]->sched_rq[entity->priority];
  94. }
  95. init_completion(&entity->entity_idle);
  96. /* We start in an idle state. */
  97. complete_all(&entity->entity_idle);
  98. spin_lock_init(&entity->rq_lock);
  99. spsc_queue_init(&entity->job_queue);
  100. atomic_set(&entity->fence_seq, 0);
  101. entity->fence_context = dma_fence_context_alloc(2);
  102. return 0;
  103. }
  104. EXPORT_SYMBOL(drm_sched_entity_init);
  105. /**
  106. * drm_sched_entity_modify_sched - Modify sched of an entity
  107. * @entity: scheduler entity to init
  108. * @sched_list: the list of new drm scheds which will replace
  109. * existing entity->sched_list
  110. * @num_sched_list: number of drm sched in sched_list
  111. *
  112. * Note that this must be called under the same common lock for @entity as
  113. * drm_sched_job_arm() and drm_sched_entity_push_job(), or the driver needs to
  114. * guarantee through some other means that this is never called while new jobs
  115. * can be pushed to @entity.
  116. */
  117. void drm_sched_entity_modify_sched(struct drm_sched_entity *entity,
  118. struct drm_gpu_scheduler **sched_list,
  119. unsigned int num_sched_list)
  120. {
  121. WARN_ON(!num_sched_list || !sched_list);
  122. spin_lock(&entity->rq_lock);
  123. entity->sched_list = sched_list;
  124. entity->num_sched_list = num_sched_list;
  125. spin_unlock(&entity->rq_lock);
  126. }
  127. EXPORT_SYMBOL(drm_sched_entity_modify_sched);
  128. static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity)
  129. {
  130. rmb(); /* for list_empty to work without lock */
  131. if (list_empty(&entity->list) ||
  132. spsc_queue_count(&entity->job_queue) == 0 ||
  133. entity->stopped)
  134. return true;
  135. return false;
  136. }
  137. /* Return true if entity could provide a job. */
  138. bool drm_sched_entity_is_ready(struct drm_sched_entity *entity)
  139. {
  140. if (spsc_queue_peek(&entity->job_queue) == NULL)
  141. return false;
  142. if (READ_ONCE(entity->dependency))
  143. return false;
  144. return true;
  145. }
  146. /**
  147. * drm_sched_entity_error - return error of last scheduled job
  148. * @entity: scheduler entity to check
  149. *
  150. * Opportunistically return the error of the last scheduled job. Result can
  151. * change any time when new jobs are pushed to the hw.
  152. */
  153. int drm_sched_entity_error(struct drm_sched_entity *entity)
  154. {
  155. struct dma_fence *fence;
  156. int r;
  157. rcu_read_lock();
  158. fence = rcu_dereference(entity->last_scheduled);
  159. r = fence ? fence->error : 0;
  160. rcu_read_unlock();
  161. return r;
  162. }
  163. EXPORT_SYMBOL(drm_sched_entity_error);
  164. static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
  165. {
  166. struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
  167. drm_sched_fence_scheduled(job->s_fence, NULL);
  168. drm_sched_fence_finished(job->s_fence, -ESRCH);
  169. WARN_ON(job->s_fence->parent);
  170. job->sched->ops->free_job(job);
  171. }
  172. /* Signal the scheduler finished fence when the entity in question is killed. */
  173. static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
  174. struct dma_fence_cb *cb)
  175. {
  176. struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
  177. finish_cb);
  178. unsigned long index;
  179. dma_fence_put(f);
  180. /* Wait for all dependencies to avoid data corruptions */
  181. xa_for_each(&job->dependencies, index, f) {
  182. struct drm_sched_fence *s_fence = to_drm_sched_fence(f);
  183. if (s_fence && f == &s_fence->scheduled) {
  184. /* The dependencies array had a reference on the scheduled
  185. * fence, and the finished fence refcount might have
  186. * dropped to zero. Use dma_fence_get_rcu() so we get
  187. * a NULL fence in that case.
  188. */
  189. f = dma_fence_get_rcu(&s_fence->finished);
  190. /* Now that we have a reference on the finished fence,
  191. * we can release the reference the dependencies array
  192. * had on the scheduled fence.
  193. */
  194. dma_fence_put(&s_fence->scheduled);
  195. }
  196. xa_erase(&job->dependencies, index);
  197. if (f && !dma_fence_add_callback(f, &job->finish_cb,
  198. drm_sched_entity_kill_jobs_cb))
  199. return;
  200. dma_fence_put(f);
  201. }
  202. INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
  203. schedule_work(&job->work);
  204. }
  205. /* Remove the entity from the scheduler and kill all pending jobs */
  206. static void drm_sched_entity_kill(struct drm_sched_entity *entity)
  207. {
  208. struct drm_sched_job *job;
  209. struct dma_fence *prev;
  210. if (!entity->rq)
  211. return;
  212. spin_lock(&entity->rq_lock);
  213. entity->stopped = true;
  214. drm_sched_rq_remove_entity(entity->rq, entity);
  215. spin_unlock(&entity->rq_lock);
  216. /* Make sure this entity is not used by the scheduler at the moment */
  217. wait_for_completion(&entity->entity_idle);
  218. /* The entity is guaranteed to not be used by the scheduler */
  219. prev = rcu_dereference_check(entity->last_scheduled, true);
  220. dma_fence_get(prev);
  221. while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) {
  222. struct drm_sched_fence *s_fence = job->s_fence;
  223. dma_fence_get(&s_fence->finished);
  224. if (!prev ||
  225. dma_fence_add_callback(prev, &job->finish_cb,
  226. drm_sched_entity_kill_jobs_cb)) {
  227. /*
  228. * Adding callback above failed.
  229. * dma_fence_put() checks for NULL.
  230. */
  231. dma_fence_put(prev);
  232. drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
  233. }
  234. prev = &s_fence->finished;
  235. }
  236. dma_fence_put(prev);
  237. }
  238. /**
  239. * drm_sched_entity_flush - Flush a context entity
  240. *
  241. * @entity: scheduler entity
  242. * @timeout: time to wait in for Q to become empty in jiffies.
  243. *
  244. * Splitting drm_sched_entity_fini() into two functions, The first one does the
  245. * waiting, removes the entity from the runqueue and returns an error when the
  246. * process was killed.
  247. *
  248. * Returns the remaining time in jiffies left from the input timeout
  249. */
  250. long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)
  251. {
  252. struct drm_gpu_scheduler *sched;
  253. struct task_struct *last_user;
  254. long ret = timeout;
  255. if (!entity->rq)
  256. return 0;
  257. sched = entity->rq->sched;
  258. /**
  259. * The client will not queue more IBs during this fini, consume existing
  260. * queued IBs or discard them on SIGKILL
  261. */
  262. if (current->flags & PF_EXITING) {
  263. if (timeout)
  264. ret = wait_event_timeout(
  265. sched->job_scheduled,
  266. drm_sched_entity_is_idle(entity),
  267. timeout);
  268. } else {
  269. wait_event_killable(sched->job_scheduled,
  270. drm_sched_entity_is_idle(entity));
  271. }
  272. /* For killed process disable any more IBs enqueue right now */
  273. last_user = cmpxchg(&entity->last_user, current->group_leader, NULL);
  274. if ((!last_user || last_user == current->group_leader) &&
  275. (current->flags & PF_EXITING) && (current->exit_code == SIGKILL))
  276. drm_sched_entity_kill(entity);
  277. return ret;
  278. }
  279. EXPORT_SYMBOL(drm_sched_entity_flush);
  280. /**
  281. * drm_sched_entity_fini - Destroy a context entity
  282. *
  283. * @entity: scheduler entity
  284. *
  285. * Cleanups up @entity which has been initialized by drm_sched_entity_init().
  286. *
  287. * If there are potentially job still in flight or getting newly queued
  288. * drm_sched_entity_flush() must be called first. This function then goes over
  289. * the entity and signals all jobs with an error code if the process was killed.
  290. */
  291. void drm_sched_entity_fini(struct drm_sched_entity *entity)
  292. {
  293. /*
  294. * If consumption of existing IBs wasn't completed. Forcefully remove
  295. * them here. Also makes sure that the scheduler won't touch this entity
  296. * any more.
  297. */
  298. drm_sched_entity_kill(entity);
  299. if (entity->dependency) {
  300. dma_fence_remove_callback(entity->dependency, &entity->cb);
  301. dma_fence_put(entity->dependency);
  302. entity->dependency = NULL;
  303. }
  304. dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
  305. RCU_INIT_POINTER(entity->last_scheduled, NULL);
  306. }
  307. EXPORT_SYMBOL(drm_sched_entity_fini);
  308. /**
  309. * drm_sched_entity_destroy - Destroy a context entity
  310. * @entity: scheduler entity
  311. *
  312. * Calls drm_sched_entity_flush() and drm_sched_entity_fini() as a
  313. * convenience wrapper.
  314. */
  315. void drm_sched_entity_destroy(struct drm_sched_entity *entity)
  316. {
  317. drm_sched_entity_flush(entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY);
  318. drm_sched_entity_fini(entity);
  319. }
  320. EXPORT_SYMBOL(drm_sched_entity_destroy);
  321. /*
  322. * drm_sched_entity_clear_dep - callback to clear the entities dependency and
  323. * wake up scheduler
  324. */
  325. static void drm_sched_entity_wakeup(struct dma_fence *f,
  326. struct dma_fence_cb *cb)
  327. {
  328. struct drm_sched_entity *entity =
  329. container_of(cb, struct drm_sched_entity, cb);
  330. entity->dependency = NULL;
  331. dma_fence_put(f);
  332. drm_sched_wakeup(entity->rq->sched);
  333. }
  334. /**
  335. * drm_sched_entity_set_priority - Sets priority of the entity
  336. *
  337. * @entity: scheduler entity
  338. * @priority: scheduler priority
  339. *
  340. * Update the priority of runqueus used for the entity.
  341. */
  342. void drm_sched_entity_set_priority(struct drm_sched_entity *entity,
  343. enum drm_sched_priority priority)
  344. {
  345. spin_lock(&entity->rq_lock);
  346. entity->priority = priority;
  347. spin_unlock(&entity->rq_lock);
  348. }
  349. EXPORT_SYMBOL(drm_sched_entity_set_priority);
  350. /*
  351. * Add a callback to the current dependency of the entity to wake up the
  352. * scheduler when the entity becomes available.
  353. */
  354. static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity)
  355. {
  356. struct drm_gpu_scheduler *sched = entity->rq->sched;
  357. struct dma_fence *fence = entity->dependency;
  358. struct drm_sched_fence *s_fence;
  359. if (fence->context == entity->fence_context ||
  360. fence->context == entity->fence_context + 1) {
  361. /*
  362. * Fence is a scheduled/finished fence from a job
  363. * which belongs to the same entity, we can ignore
  364. * fences from ourself
  365. */
  366. dma_fence_put(entity->dependency);
  367. return false;
  368. }
  369. s_fence = to_drm_sched_fence(fence);
  370. if (!fence->error && s_fence && s_fence->sched == sched &&
  371. !test_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &fence->flags)) {
  372. /*
  373. * Fence is from the same scheduler, only need to wait for
  374. * it to be scheduled
  375. */
  376. fence = dma_fence_get(&s_fence->scheduled);
  377. dma_fence_put(entity->dependency);
  378. entity->dependency = fence;
  379. }
  380. if (!dma_fence_add_callback(entity->dependency, &entity->cb,
  381. drm_sched_entity_wakeup))
  382. return true;
  383. dma_fence_put(entity->dependency);
  384. return false;
  385. }
  386. static struct dma_fence *
  387. drm_sched_job_dependency(struct drm_sched_job *job,
  388. struct drm_sched_entity *entity)
  389. {
  390. struct dma_fence *f;
  391. /* We keep the fence around, so we can iterate over all dependencies
  392. * in drm_sched_entity_kill_jobs_cb() to ensure all deps are signaled
  393. * before killing the job.
  394. */
  395. f = xa_load(&job->dependencies, job->last_dependency);
  396. if (f) {
  397. job->last_dependency++;
  398. return dma_fence_get(f);
  399. }
  400. if (job->sched->ops->prepare_job)
  401. return job->sched->ops->prepare_job(job, entity);
  402. return NULL;
  403. }
  404. struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
  405. {
  406. struct drm_sched_job *sched_job;
  407. sched_job = to_drm_sched_job(spsc_queue_peek(&entity->job_queue));
  408. if (!sched_job)
  409. return NULL;
  410. while ((entity->dependency =
  411. drm_sched_job_dependency(sched_job, entity))) {
  412. trace_drm_sched_job_wait_dep(sched_job, entity->dependency);
  413. if (drm_sched_entity_add_dependency_cb(entity))
  414. return NULL;
  415. }
  416. /* skip jobs from entity that marked guilty */
  417. if (entity->guilty && atomic_read(entity->guilty))
  418. dma_fence_set_error(&sched_job->s_fence->finished, -ECANCELED);
  419. dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
  420. rcu_assign_pointer(entity->last_scheduled,
  421. dma_fence_get(&sched_job->s_fence->finished));
  422. /*
  423. * If the queue is empty we allow drm_sched_entity_select_rq() to
  424. * locklessly access ->last_scheduled. This only works if we set the
  425. * pointer before we dequeue and if we a write barrier here.
  426. */
  427. smp_wmb();
  428. spsc_queue_pop(&entity->job_queue);
  429. /*
  430. * Update the entity's location in the min heap according to
  431. * the timestamp of the next job, if any.
  432. */
  433. if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) {
  434. struct drm_sched_job *next;
  435. next = to_drm_sched_job(spsc_queue_peek(&entity->job_queue));
  436. if (next)
  437. drm_sched_rq_update_fifo(entity, next->submit_ts);
  438. }
  439. /* Jobs and entities might have different lifecycles. Since we're
  440. * removing the job from the entities queue, set the jobs entity pointer
  441. * to NULL to prevent any future access of the entity through this job.
  442. */
  443. sched_job->entity = NULL;
  444. return sched_job;
  445. }
  446. void drm_sched_entity_select_rq(struct drm_sched_entity *entity)
  447. {
  448. struct dma_fence *fence;
  449. struct drm_gpu_scheduler *sched;
  450. struct drm_sched_rq *rq;
  451. /* single possible engine and already selected */
  452. if (!entity->sched_list)
  453. return;
  454. /* queue non-empty, stay on the same engine */
  455. if (spsc_queue_count(&entity->job_queue))
  456. return;
  457. /*
  458. * Only when the queue is empty are we guaranteed that the scheduler
  459. * thread cannot change ->last_scheduled. To enforce ordering we need
  460. * a read barrier here. See drm_sched_entity_pop_job() for the other
  461. * side.
  462. */
  463. smp_rmb();
  464. fence = rcu_dereference_check(entity->last_scheduled, true);
  465. /* stay on the same engine if the previous job hasn't finished */
  466. if (fence && !dma_fence_is_signaled(fence))
  467. return;
  468. spin_lock(&entity->rq_lock);
  469. sched = drm_sched_pick_best(entity->sched_list, entity->num_sched_list);
  470. rq = sched ? sched->sched_rq[entity->priority] : NULL;
  471. if (rq != entity->rq) {
  472. drm_sched_rq_remove_entity(entity->rq, entity);
  473. entity->rq = rq;
  474. }
  475. spin_unlock(&entity->rq_lock);
  476. if (entity->num_sched_list == 1)
  477. entity->sched_list = NULL;
  478. }
  479. /**
  480. * drm_sched_entity_push_job - Submit a job to the entity's job queue
  481. * @sched_job: job to submit
  482. *
  483. * Note: To guarantee that the order of insertion to queue matches the job's
  484. * fence sequence number this function should be called with drm_sched_job_arm()
  485. * under common lock for the struct drm_sched_entity that was set up for
  486. * @sched_job in drm_sched_job_init().
  487. *
  488. * Returns 0 for success, negative error code otherwise.
  489. */
  490. void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
  491. {
  492. struct drm_sched_entity *entity = sched_job->entity;
  493. bool first;
  494. ktime_t submit_ts;
  495. trace_drm_sched_job(sched_job, entity);
  496. atomic_inc(entity->rq->sched->score);
  497. WRITE_ONCE(entity->last_user, current->group_leader);
  498. /*
  499. * After the sched_job is pushed into the entity queue, it may be
  500. * completed and freed up at any time. We can no longer access it.
  501. * Make sure to set the submit_ts first, to avoid a race.
  502. */
  503. sched_job->submit_ts = submit_ts = ktime_get();
  504. first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
  505. /* first job wakes up scheduler */
  506. if (first) {
  507. struct drm_gpu_scheduler *sched;
  508. struct drm_sched_rq *rq;
  509. /* Add the entity to the run queue */
  510. spin_lock(&entity->rq_lock);
  511. if (entity->stopped) {
  512. spin_unlock(&entity->rq_lock);
  513. DRM_ERROR("Trying to push to a killed entity\n");
  514. return;
  515. }
  516. rq = entity->rq;
  517. sched = rq->sched;
  518. drm_sched_rq_add_entity(rq, entity);
  519. spin_unlock(&entity->rq_lock);
  520. if (drm_sched_policy == DRM_SCHED_POLICY_FIFO)
  521. drm_sched_rq_update_fifo(entity, submit_ts);
  522. drm_sched_wakeup(sched);
  523. }
  524. }
  525. EXPORT_SYMBOL(drm_sched_entity_push_job);