mock_engine.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Copyright © 2016 Intel Corporation
  4. */
  5. #include "gem/i915_gem_context.h"
  6. #include "gt/intel_ring.h"
  7. #include "i915_drv.h"
  8. #include "intel_context.h"
  9. #include "intel_engine_pm.h"
  10. #include "mock_engine.h"
  11. #include "selftests/mock_request.h"
  12. static int mock_timeline_pin(struct intel_timeline *tl)
  13. {
  14. int err;
  15. if (WARN_ON(!i915_gem_object_trylock(tl->hwsp_ggtt->obj, NULL)))
  16. return -EBUSY;
  17. err = intel_timeline_pin_map(tl);
  18. i915_gem_object_unlock(tl->hwsp_ggtt->obj);
  19. if (err)
  20. return err;
  21. atomic_inc(&tl->pin_count);
  22. return 0;
  23. }
  24. static void mock_timeline_unpin(struct intel_timeline *tl)
  25. {
  26. GEM_BUG_ON(!atomic_read(&tl->pin_count));
  27. atomic_dec(&tl->pin_count);
  28. }
  29. static struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size)
  30. {
  31. struct i915_address_space *vm = &ggtt->vm;
  32. struct drm_i915_private *i915 = vm->i915;
  33. struct drm_i915_gem_object *obj;
  34. struct i915_vma *vma;
  35. obj = i915_gem_object_create_internal(i915, size);
  36. if (IS_ERR(obj))
  37. return ERR_CAST(obj);
  38. vma = i915_vma_instance(obj, vm, NULL);
  39. if (IS_ERR(vma))
  40. goto err;
  41. return vma;
  42. err:
  43. i915_gem_object_put(obj);
  44. return vma;
  45. }
  46. static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
  47. {
  48. const unsigned long sz = PAGE_SIZE;
  49. struct intel_ring *ring;
  50. ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL);
  51. if (!ring)
  52. return NULL;
  53. kref_init(&ring->ref);
  54. ring->size = sz;
  55. ring->effective_size = sz;
  56. ring->vaddr = (void *)(ring + 1);
  57. atomic_set(&ring->pin_count, 1);
  58. ring->vma = create_ring_vma(engine->gt->ggtt, PAGE_SIZE);
  59. if (IS_ERR(ring->vma)) {
  60. kfree(ring);
  61. return NULL;
  62. }
  63. intel_ring_update_space(ring);
  64. return ring;
  65. }
  66. static void mock_ring_free(struct intel_ring *ring)
  67. {
  68. i915_vma_put(ring->vma);
  69. kfree(ring);
  70. }
  71. static struct i915_request *first_request(struct mock_engine *engine)
  72. {
  73. return list_first_entry_or_null(&engine->hw_queue,
  74. struct i915_request,
  75. mock.link);
  76. }
  77. static void advance(struct i915_request *request)
  78. {
  79. list_del_init(&request->mock.link);
  80. i915_request_mark_complete(request);
  81. GEM_BUG_ON(!i915_request_completed(request));
  82. intel_engine_signal_breadcrumbs(request->engine);
  83. }
  84. static void hw_delay_complete(struct timer_list *t)
  85. {
  86. struct mock_engine *engine = timer_container_of(engine, t, hw_delay);
  87. struct i915_request *request;
  88. unsigned long flags;
  89. spin_lock_irqsave(&engine->hw_lock, flags);
  90. /* Timer fired, first request is complete */
  91. request = first_request(engine);
  92. if (request)
  93. advance(request);
  94. /*
  95. * Also immediately signal any subsequent 0-delay requests, but
  96. * requeue the timer for the next delayed request.
  97. */
  98. while ((request = first_request(engine))) {
  99. if (request->mock.delay) {
  100. mod_timer(&engine->hw_delay,
  101. jiffies + request->mock.delay);
  102. break;
  103. }
  104. advance(request);
  105. }
  106. spin_unlock_irqrestore(&engine->hw_lock, flags);
  107. }
  108. static void mock_context_unpin(struct intel_context *ce)
  109. {
  110. }
  111. static void mock_context_post_unpin(struct intel_context *ce)
  112. {
  113. i915_vma_unpin(ce->ring->vma);
  114. }
  115. static void mock_context_destroy(struct kref *ref)
  116. {
  117. struct intel_context *ce = container_of(ref, typeof(*ce), ref);
  118. GEM_BUG_ON(intel_context_is_pinned(ce));
  119. if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
  120. mock_ring_free(ce->ring);
  121. mock_timeline_unpin(ce->timeline);
  122. }
  123. intel_context_fini(ce);
  124. intel_context_free(ce);
  125. }
  126. static int mock_context_alloc(struct intel_context *ce)
  127. {
  128. int err;
  129. ce->ring = mock_ring(ce->engine);
  130. if (!ce->ring)
  131. return -ENOMEM;
  132. ce->timeline = intel_timeline_create(ce->engine->gt);
  133. if (IS_ERR(ce->timeline)) {
  134. kfree(ce->engine);
  135. return PTR_ERR(ce->timeline);
  136. }
  137. err = mock_timeline_pin(ce->timeline);
  138. if (err) {
  139. intel_timeline_put(ce->timeline);
  140. ce->timeline = NULL;
  141. return err;
  142. }
  143. return 0;
  144. }
  145. static int mock_context_pre_pin(struct intel_context *ce,
  146. struct i915_gem_ww_ctx *ww, void **unused)
  147. {
  148. return i915_vma_pin_ww(ce->ring->vma, ww, 0, 0, PIN_GLOBAL | PIN_HIGH);
  149. }
  150. static int mock_context_pin(struct intel_context *ce, void *unused)
  151. {
  152. return 0;
  153. }
  154. static void mock_context_reset(struct intel_context *ce)
  155. {
  156. }
  157. static const struct intel_context_ops mock_context_ops = {
  158. .alloc = mock_context_alloc,
  159. .pre_pin = mock_context_pre_pin,
  160. .pin = mock_context_pin,
  161. .unpin = mock_context_unpin,
  162. .post_unpin = mock_context_post_unpin,
  163. .enter = intel_context_enter_engine,
  164. .exit = intel_context_exit_engine,
  165. .reset = mock_context_reset,
  166. .destroy = mock_context_destroy,
  167. };
  168. static int mock_request_alloc(struct i915_request *request)
  169. {
  170. INIT_LIST_HEAD(&request->mock.link);
  171. request->mock.delay = 0;
  172. return 0;
  173. }
  174. static int mock_emit_flush(struct i915_request *request,
  175. unsigned int flags)
  176. {
  177. return 0;
  178. }
  179. static u32 *mock_emit_breadcrumb(struct i915_request *request, u32 *cs)
  180. {
  181. return cs;
  182. }
  183. static void mock_submit_request(struct i915_request *request)
  184. {
  185. struct mock_engine *engine =
  186. container_of(request->engine, typeof(*engine), base);
  187. unsigned long flags;
  188. i915_request_submit(request);
  189. spin_lock_irqsave(&engine->hw_lock, flags);
  190. list_add_tail(&request->mock.link, &engine->hw_queue);
  191. if (list_is_first(&request->mock.link, &engine->hw_queue)) {
  192. if (request->mock.delay)
  193. mod_timer(&engine->hw_delay,
  194. jiffies + request->mock.delay);
  195. else
  196. advance(request);
  197. }
  198. spin_unlock_irqrestore(&engine->hw_lock, flags);
  199. }
  200. static void mock_add_to_engine(struct i915_request *rq)
  201. {
  202. lockdep_assert_held(&rq->engine->sched_engine->lock);
  203. list_move_tail(&rq->sched.link, &rq->engine->sched_engine->requests);
  204. }
  205. static void mock_remove_from_engine(struct i915_request *rq)
  206. {
  207. struct intel_engine_cs *engine, *locked;
  208. /*
  209. * Virtual engines complicate acquiring the engine timeline lock,
  210. * as their rq->engine pointer is not stable until under that
  211. * engine lock. The simple ploy we use is to take the lock then
  212. * check that the rq still belongs to the newly locked engine.
  213. */
  214. locked = READ_ONCE(rq->engine);
  215. spin_lock_irq(&locked->sched_engine->lock);
  216. while (unlikely(locked != (engine = READ_ONCE(rq->engine)))) {
  217. spin_unlock(&locked->sched_engine->lock);
  218. spin_lock(&engine->sched_engine->lock);
  219. locked = engine;
  220. }
  221. list_del_init(&rq->sched.link);
  222. spin_unlock_irq(&locked->sched_engine->lock);
  223. }
  224. static void mock_reset_prepare(struct intel_engine_cs *engine)
  225. {
  226. }
  227. static void mock_reset_rewind(struct intel_engine_cs *engine, bool stalled)
  228. {
  229. GEM_BUG_ON(stalled);
  230. }
  231. static void mock_reset_cancel(struct intel_engine_cs *engine)
  232. {
  233. struct mock_engine *mock =
  234. container_of(engine, typeof(*mock), base);
  235. struct i915_request *rq;
  236. unsigned long flags;
  237. timer_delete_sync(&mock->hw_delay);
  238. spin_lock_irqsave(&engine->sched_engine->lock, flags);
  239. /* Mark all submitted requests as skipped. */
  240. list_for_each_entry(rq, &engine->sched_engine->requests, sched.link)
  241. i915_request_put(i915_request_mark_eio(rq));
  242. intel_engine_signal_breadcrumbs(engine);
  243. /* Cancel and submit all pending requests. */
  244. list_for_each_entry(rq, &mock->hw_queue, mock.link) {
  245. if (i915_request_mark_eio(rq)) {
  246. __i915_request_submit(rq);
  247. i915_request_put(rq);
  248. }
  249. }
  250. INIT_LIST_HEAD(&mock->hw_queue);
  251. spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
  252. }
  253. static void mock_reset_finish(struct intel_engine_cs *engine)
  254. {
  255. }
  256. static void mock_engine_release(struct intel_engine_cs *engine)
  257. {
  258. struct mock_engine *mock =
  259. container_of(engine, typeof(*mock), base);
  260. GEM_BUG_ON(timer_pending(&mock->hw_delay));
  261. i915_sched_engine_put(engine->sched_engine);
  262. intel_breadcrumbs_put(engine->breadcrumbs);
  263. intel_context_unpin(engine->kernel_context);
  264. intel_context_put(engine->kernel_context);
  265. intel_engine_fini_retire(engine);
  266. }
  267. struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
  268. const char *name,
  269. int id)
  270. {
  271. struct mock_engine *engine;
  272. GEM_BUG_ON(id >= I915_NUM_ENGINES);
  273. GEM_BUG_ON(!to_gt(i915)->uncore);
  274. engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL);
  275. if (!engine)
  276. return NULL;
  277. /* minimal engine setup for requests */
  278. engine->base.i915 = i915;
  279. engine->base.gt = to_gt(i915);
  280. engine->base.uncore = to_gt(i915)->uncore;
  281. snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
  282. engine->base.id = id;
  283. engine->base.mask = BIT(id);
  284. engine->base.legacy_idx = INVALID_ENGINE;
  285. engine->base.instance = id;
  286. engine->base.status_page.addr = (void *)(engine + 1);
  287. engine->base.cops = &mock_context_ops;
  288. engine->base.request_alloc = mock_request_alloc;
  289. engine->base.emit_flush = mock_emit_flush;
  290. engine->base.emit_fini_breadcrumb = mock_emit_breadcrumb;
  291. engine->base.submit_request = mock_submit_request;
  292. engine->base.add_active_request = mock_add_to_engine;
  293. engine->base.remove_active_request = mock_remove_from_engine;
  294. engine->base.reset.prepare = mock_reset_prepare;
  295. engine->base.reset.rewind = mock_reset_rewind;
  296. engine->base.reset.cancel = mock_reset_cancel;
  297. engine->base.reset.finish = mock_reset_finish;
  298. engine->base.release = mock_engine_release;
  299. to_gt(i915)->engine[id] = &engine->base;
  300. to_gt(i915)->engine_class[0][id] = &engine->base;
  301. /* fake hw queue */
  302. spin_lock_init(&engine->hw_lock);
  303. timer_setup(&engine->hw_delay, hw_delay_complete, 0);
  304. INIT_LIST_HEAD(&engine->hw_queue);
  305. intel_engine_add_user(&engine->base);
  306. return &engine->base;
  307. }
  308. int mock_engine_init(struct intel_engine_cs *engine)
  309. {
  310. struct intel_context *ce;
  311. INIT_LIST_HEAD(&engine->pinned_contexts_list);
  312. engine->sched_engine = i915_sched_engine_create(ENGINE_MOCK);
  313. if (!engine->sched_engine)
  314. return -ENOMEM;
  315. engine->sched_engine->private_data = engine;
  316. intel_engine_init_execlists(engine);
  317. intel_engine_init__pm(engine);
  318. intel_engine_init_retire(engine);
  319. engine->breadcrumbs = intel_breadcrumbs_create(NULL);
  320. if (!engine->breadcrumbs)
  321. goto err_schedule;
  322. ce = create_kernel_context(engine);
  323. if (IS_ERR(ce))
  324. goto err_breadcrumbs;
  325. /* We insist the kernel context is using the status_page */
  326. engine->status_page.vma = ce->timeline->hwsp_ggtt;
  327. engine->kernel_context = ce;
  328. return 0;
  329. err_breadcrumbs:
  330. intel_breadcrumbs_put(engine->breadcrumbs);
  331. err_schedule:
  332. i915_sched_engine_put(engine->sched_engine);
  333. return -ENOMEM;
  334. }
  335. void mock_engine_flush(struct intel_engine_cs *engine)
  336. {
  337. struct mock_engine *mock =
  338. container_of(engine, typeof(*mock), base);
  339. struct i915_request *request, *rn;
  340. timer_delete_sync(&mock->hw_delay);
  341. spin_lock_irq(&mock->hw_lock);
  342. list_for_each_entry_safe(request, rn, &mock->hw_queue, mock.link)
  343. advance(request);
  344. spin_unlock_irq(&mock->hw_lock);
  345. }
  346. void mock_engine_reset(struct intel_engine_cs *engine)
  347. {
  348. }