Commit | Line | Data |
---|---|---|
f97fbf96 CW |
1 | /* |
2 | * Copyright © 2016 Intel Corporation | |
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 (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | */ | |
24 | ||
10be98a7 | 25 | #include "gem/i915_gem_context.h" |
2871ea85 | 26 | #include "gt/intel_ring.h" |
10be98a7 | 27 | |
112ed2d3 CW |
28 | #include "i915_drv.h" |
29 | #include "intel_context.h" | |
79ffac85 | 30 | #include "intel_engine_pm.h" |
b40d7378 | 31 | #include "intel_engine_pool.h" |
112ed2d3 | 32 | |
f97fbf96 | 33 | #include "mock_engine.h" |
112ed2d3 | 34 | #include "selftests/mock_request.h" |
f97fbf96 | 35 | |
f0c02c1b | 36 | static void mock_timeline_pin(struct intel_timeline *tl) |
5013eb8c | 37 | { |
ccb23d2d | 38 | atomic_inc(&tl->pin_count); |
5013eb8c CW |
39 | } |
40 | ||
f0c02c1b | 41 | static void mock_timeline_unpin(struct intel_timeline *tl) |
5013eb8c | 42 | { |
ccb23d2d CW |
43 | GEM_BUG_ON(!atomic_read(&tl->pin_count)); |
44 | atomic_dec(&tl->pin_count); | |
5013eb8c CW |
45 | } |
46 | ||
209760b7 CW |
47 | static struct intel_ring *mock_ring(struct intel_engine_cs *engine) |
48 | { | |
49 | const unsigned long sz = PAGE_SIZE / 2; | |
75d0a7f3 | 50 | struct intel_ring *ring; |
209760b7 CW |
51 | |
52 | ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); | |
53 | if (!ring) | |
54 | return NULL; | |
55 | ||
75d0a7f3 CW |
56 | kref_init(&ring->ref); |
57 | ring->size = sz; | |
58 | ring->effective_size = sz; | |
59 | ring->vaddr = (void *)(ring + 1); | |
60 | atomic_set(&ring->pin_count, 1); | |
209760b7 | 61 | |
1fdea0cb CW |
62 | ring->vma = i915_vma_alloc(); |
63 | if (!ring->vma) { | |
64 | kfree(ring); | |
65 | return NULL; | |
66 | } | |
67 | i915_active_init(&ring->vma->active, NULL, NULL); | |
68 | ||
75d0a7f3 | 69 | intel_ring_update_space(ring); |
209760b7 | 70 | |
75d0a7f3 | 71 | return ring; |
209760b7 CW |
72 | } |
73 | ||
1fdea0cb CW |
74 | static void mock_ring_free(struct intel_ring *ring) |
75 | { | |
76 | i915_active_fini(&ring->vma->active); | |
77 | i915_vma_free(ring->vma); | |
78 | ||
79 | kfree(ring); | |
80 | } | |
81 | ||
32eb6bcf | 82 | static struct i915_request *first_request(struct mock_engine *engine) |
f97fbf96 | 83 | { |
0daf0113 | 84 | return list_first_entry_or_null(&engine->hw_queue, |
32eb6bcf CW |
85 | struct i915_request, |
86 | mock.link); | |
0daf0113 CW |
87 | } |
88 | ||
32eb6bcf | 89 | static void advance(struct i915_request *request) |
b1f9107e | 90 | { |
32eb6bcf CW |
91 | list_del_init(&request->mock.link); |
92 | i915_request_mark_complete(request); | |
93 | GEM_BUG_ON(!i915_request_completed(request)); | |
52c0fdb2 | 94 | |
54400257 | 95 | intel_engine_signal_breadcrumbs(request->engine); |
b1f9107e CW |
96 | } |
97 | ||
39cbf2aa | 98 | static void hw_delay_complete(struct timer_list *t) |
0daf0113 | 99 | { |
39cbf2aa | 100 | struct mock_engine *engine = from_timer(engine, t, hw_delay); |
32eb6bcf | 101 | struct i915_request *request; |
52c0fdb2 | 102 | unsigned long flags; |
0daf0113 | 103 | |
52c0fdb2 | 104 | spin_lock_irqsave(&engine->hw_lock, flags); |
0daf0113 | 105 | |
b1f9107e | 106 | /* Timer fired, first request is complete */ |
0daf0113 CW |
107 | request = first_request(engine); |
108 | if (request) | |
1579ab2d | 109 | advance(request); |
b1f9107e CW |
110 | |
111 | /* | |
112 | * Also immediately signal any subsequent 0-delay requests, but | |
113 | * requeue the timer for the next delayed request. | |
114 | */ | |
115 | while ((request = first_request(engine))) { | |
32eb6bcf CW |
116 | if (request->mock.delay) { |
117 | mod_timer(&engine->hw_delay, | |
118 | jiffies + request->mock.delay); | |
b1f9107e CW |
119 | break; |
120 | } | |
121 | ||
1579ab2d | 122 | advance(request); |
b1f9107e | 123 | } |
0daf0113 | 124 | |
52c0fdb2 | 125 | spin_unlock_irqrestore(&engine->hw_lock, flags); |
0daf0113 CW |
126 | } |
127 | ||
1fc44d9b | 128 | static void mock_context_unpin(struct intel_context *ce) |
0daf0113 | 129 | { |
1fc44d9b | 130 | } |
ab82a063 | 131 | |
4c5896dc | 132 | static void mock_context_destroy(struct kref *ref) |
1fc44d9b | 133 | { |
4c5896dc CW |
134 | struct intel_context *ce = container_of(ref, typeof(*ce), ref); |
135 | ||
08819549 | 136 | GEM_BUG_ON(intel_context_is_pinned(ce)); |
209760b7 | 137 | |
75d0a7f3 | 138 | if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { |
1fdea0cb | 139 | mock_ring_free(ce->ring); |
75d0a7f3 CW |
140 | mock_timeline_unpin(ce->timeline); |
141 | } | |
4c5896dc | 142 | |
df8cf31e | 143 | intel_context_fini(ce); |
4c5896dc | 144 | intel_context_free(ce); |
0daf0113 CW |
145 | } |
146 | ||
4c60b1aa CW |
147 | static int mock_context_alloc(struct intel_context *ce) |
148 | { | |
149 | ce->ring = mock_ring(ce->engine); | |
150 | if (!ce->ring) | |
151 | return -ENOMEM; | |
152 | ||
75d0a7f3 CW |
153 | GEM_BUG_ON(ce->timeline); |
154 | ce->timeline = intel_timeline_create(ce->engine->gt, NULL); | |
155 | if (IS_ERR(ce->timeline)) { | |
156 | kfree(ce->engine); | |
157 | return PTR_ERR(ce->timeline); | |
158 | } | |
159 | ||
160 | mock_timeline_pin(ce->timeline); | |
161 | ||
4c60b1aa CW |
162 | return 0; |
163 | } | |
164 | ||
95f697eb | 165 | static int mock_context_pin(struct intel_context *ce) |
0daf0113 | 166 | { |
b11b28ea | 167 | return 0; |
0daf0113 CW |
168 | } |
169 | ||
fb218f20 CW |
170 | static void mock_context_reset(struct intel_context *ce) |
171 | { | |
172 | } | |
173 | ||
4dc84b77 | 174 | static const struct intel_context_ops mock_context_ops = { |
4c60b1aa CW |
175 | .alloc = mock_context_alloc, |
176 | ||
95f697eb | 177 | .pin = mock_context_pin, |
4dc84b77 | 178 | .unpin = mock_context_unpin, |
4c5896dc | 179 | |
6eee33e8 CW |
180 | .enter = intel_context_enter_engine, |
181 | .exit = intel_context_exit_engine, | |
182 | ||
fb218f20 | 183 | .reset = mock_context_reset, |
4dc84b77 CW |
184 | .destroy = mock_context_destroy, |
185 | }; | |
186 | ||
e61e0f51 | 187 | static int mock_request_alloc(struct i915_request *request) |
0daf0113 | 188 | { |
32eb6bcf CW |
189 | INIT_LIST_HEAD(&request->mock.link); |
190 | request->mock.delay = 0; | |
0daf0113 | 191 | |
0daf0113 CW |
192 | return 0; |
193 | } | |
194 | ||
e61e0f51 | 195 | static int mock_emit_flush(struct i915_request *request, |
0daf0113 CW |
196 | unsigned int flags) |
197 | { | |
198 | return 0; | |
199 | } | |
200 | ||
e1a73a54 | 201 | static u32 *mock_emit_breadcrumb(struct i915_request *request, u32 *cs) |
0daf0113 | 202 | { |
e1a73a54 | 203 | return cs; |
0daf0113 CW |
204 | } |
205 | ||
e61e0f51 | 206 | static void mock_submit_request(struct i915_request *request) |
0daf0113 | 207 | { |
0daf0113 CW |
208 | struct mock_engine *engine = |
209 | container_of(request->engine, typeof(*engine), base); | |
52c0fdb2 | 210 | unsigned long flags; |
0daf0113 | 211 | |
e61e0f51 | 212 | i915_request_submit(request); |
0daf0113 | 213 | |
52c0fdb2 | 214 | spin_lock_irqsave(&engine->hw_lock, flags); |
32eb6bcf CW |
215 | list_add_tail(&request->mock.link, &engine->hw_queue); |
216 | if (list_is_first(&request->mock.link, &engine->hw_queue)) { | |
217 | if (request->mock.delay) | |
218 | mod_timer(&engine->hw_delay, | |
219 | jiffies + request->mock.delay); | |
b1f9107e | 220 | else |
32eb6bcf | 221 | advance(request); |
b1f9107e | 222 | } |
52c0fdb2 | 223 | spin_unlock_irqrestore(&engine->hw_lock, flags); |
0daf0113 CW |
224 | } |
225 | ||
d315d4fa CW |
226 | static void mock_reset_prepare(struct intel_engine_cs *engine) |
227 | { | |
228 | } | |
229 | ||
e26b6d43 | 230 | static void mock_reset_rewind(struct intel_engine_cs *engine, bool stalled) |
d315d4fa CW |
231 | { |
232 | GEM_BUG_ON(stalled); | |
233 | } | |
234 | ||
e26b6d43 | 235 | static void mock_reset_cancel(struct intel_engine_cs *engine) |
d315d4fa CW |
236 | { |
237 | struct i915_request *request; | |
238 | unsigned long flags; | |
239 | ||
422d7df4 | 240 | spin_lock_irqsave(&engine->active.lock, flags); |
d315d4fa CW |
241 | |
242 | /* Mark all submitted requests as skipped. */ | |
422d7df4 | 243 | list_for_each_entry(request, &engine->active.requests, sched.link) { |
d315d4fa CW |
244 | if (!i915_request_signaled(request)) |
245 | dma_fence_set_error(&request->fence, -EIO); | |
246 | ||
247 | i915_request_mark_complete(request); | |
248 | } | |
249 | ||
422d7df4 | 250 | spin_unlock_irqrestore(&engine->active.lock, flags); |
d315d4fa CW |
251 | } |
252 | ||
e26b6d43 CW |
253 | static void mock_reset_finish(struct intel_engine_cs *engine) |
254 | { | |
255 | } | |
256 | ||
257 | static void mock_engine_release(struct intel_engine_cs *engine) | |
258 | { | |
259 | struct mock_engine *mock = | |
260 | container_of(engine, typeof(*mock), base); | |
261 | ||
262 | GEM_BUG_ON(timer_pending(&mock->hw_delay)); | |
263 | ||
264 | intel_context_unpin(engine->kernel_context); | |
265 | intel_context_put(engine->kernel_context); | |
266 | ||
267 | intel_engine_fini_retire(engine); | |
268 | intel_engine_fini_breadcrumbs(engine); | |
269 | } | |
270 | ||
0daf0113 | 271 | struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, |
3ec0af7f CW |
272 | const char *name, |
273 | int id) | |
0daf0113 CW |
274 | { |
275 | struct mock_engine *engine; | |
3ec0af7f CW |
276 | |
277 | GEM_BUG_ON(id >= I915_NUM_ENGINES); | |
d14a701b | 278 | GEM_BUG_ON(!i915->gt.uncore); |
f97fbf96 CW |
279 | |
280 | engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL); | |
281 | if (!engine) | |
282 | return NULL; | |
283 | ||
0daf0113 CW |
284 | /* minimal engine setup for requests */ |
285 | engine->base.i915 = i915; | |
f937f561 | 286 | engine->base.gt = &i915->gt; |
3de16278 | 287 | engine->base.uncore = i915->gt.uncore; |
6e516148 | 288 | snprintf(engine->base.name, sizeof(engine->base.name), "%s", name); |
3ec0af7f | 289 | engine->base.id = id; |
8a68d464 | 290 | engine->base.mask = BIT(id); |
bcce7d90 | 291 | engine->base.legacy_idx = INVALID_ENGINE; |
cbb153c5 | 292 | engine->base.instance = id; |
0ca88ba0 | 293 | engine->base.status_page.addr = (void *)(engine + 1); |
f97fbf96 | 294 | |
4dc84b77 | 295 | engine->base.cops = &mock_context_ops; |
0daf0113 CW |
296 | engine->base.request_alloc = mock_request_alloc; |
297 | engine->base.emit_flush = mock_emit_flush; | |
85474441 | 298 | engine->base.emit_fini_breadcrumb = mock_emit_breadcrumb; |
0daf0113 CW |
299 | engine->base.submit_request = mock_submit_request; |
300 | ||
d315d4fa | 301 | engine->base.reset.prepare = mock_reset_prepare; |
e26b6d43 CW |
302 | engine->base.reset.rewind = mock_reset_rewind; |
303 | engine->base.reset.cancel = mock_reset_cancel; | |
d315d4fa | 304 | engine->base.reset.finish = mock_reset_finish; |
e26b6d43 CW |
305 | |
306 | engine->base.release = mock_engine_release; | |
d315d4fa | 307 | |
bcce7d90 CW |
308 | i915->gt.engine[id] = &engine->base; |
309 | i915->gt.engine_class[0][id] = &engine->base; | |
310 | ||
0daf0113 CW |
311 | /* fake hw queue */ |
312 | spin_lock_init(&engine->hw_lock); | |
39cbf2aa | 313 | timer_setup(&engine->hw_delay, hw_delay_complete, 0); |
0daf0113 CW |
314 | INIT_LIST_HEAD(&engine->hw_queue); |
315 | ||
cbb153c5 CW |
316 | intel_engine_add_user(&engine->base); |
317 | ||
11334c6a CW |
318 | return &engine->base; |
319 | } | |
320 | ||
321 | int mock_engine_init(struct intel_engine_cs *engine) | |
322 | { | |
38775829 | 323 | struct intel_context *ce; |
11334c6a | 324 | |
422d7df4 | 325 | intel_engine_init_active(engine, ENGINE_MOCK); |
11334c6a CW |
326 | intel_engine_init_breadcrumbs(engine); |
327 | intel_engine_init_execlists(engine); | |
328 | intel_engine_init__pm(engine); | |
ed7dd73c | 329 | intel_engine_init_retire(engine); |
b40d7378 | 330 | intel_engine_pool_init(&engine->pool); |
11334c6a | 331 | |
38775829 CW |
332 | ce = create_kernel_context(engine); |
333 | if (IS_ERR(ce)) | |
422d7df4 | 334 | goto err_breadcrumbs; |
fa9f6681 | 335 | |
38775829 | 336 | engine->kernel_context = ce; |
11334c6a | 337 | return 0; |
b887d615 CW |
338 | |
339 | err_breadcrumbs: | |
11334c6a CW |
340 | intel_engine_fini_breadcrumbs(engine); |
341 | return -ENOMEM; | |
f97fbf96 CW |
342 | } |
343 | ||
344 | void mock_engine_flush(struct intel_engine_cs *engine) | |
345 | { | |
0daf0113 CW |
346 | struct mock_engine *mock = |
347 | container_of(engine, typeof(*mock), base); | |
32eb6bcf | 348 | struct i915_request *request, *rn; |
0daf0113 CW |
349 | |
350 | del_timer_sync(&mock->hw_delay); | |
351 | ||
352 | spin_lock_irq(&mock->hw_lock); | |
32eb6bcf | 353 | list_for_each_entry_safe(request, rn, &mock->hw_queue, mock.link) |
1579ab2d | 354 | advance(request); |
0daf0113 | 355 | spin_unlock_irq(&mock->hw_lock); |
f97fbf96 CW |
356 | } |
357 | ||
358 | void mock_engine_reset(struct intel_engine_cs *engine) | |
359 | { | |
f97fbf96 | 360 | } |