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 CW |
25 | #include "gem/i915_gem_context.h" |
26 | ||
112ed2d3 CW |
27 | #include "i915_drv.h" |
28 | #include "intel_context.h" | |
79ffac85 | 29 | #include "intel_engine_pm.h" |
b40d7378 | 30 | #include "intel_engine_pool.h" |
112ed2d3 | 31 | |
f97fbf96 | 32 | #include "mock_engine.h" |
112ed2d3 | 33 | #include "selftests/mock_request.h" |
f97fbf96 | 34 | |
f0c02c1b | 35 | static void mock_timeline_pin(struct intel_timeline *tl) |
5013eb8c | 36 | { |
ccb23d2d | 37 | atomic_inc(&tl->pin_count); |
5013eb8c CW |
38 | } |
39 | ||
f0c02c1b | 40 | static void mock_timeline_unpin(struct intel_timeline *tl) |
5013eb8c | 41 | { |
ccb23d2d CW |
42 | GEM_BUG_ON(!atomic_read(&tl->pin_count)); |
43 | atomic_dec(&tl->pin_count); | |
5013eb8c CW |
44 | } |
45 | ||
209760b7 CW |
46 | static struct intel_ring *mock_ring(struct intel_engine_cs *engine) |
47 | { | |
48 | const unsigned long sz = PAGE_SIZE / 2; | |
75d0a7f3 | 49 | struct intel_ring *ring; |
209760b7 CW |
50 | |
51 | ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); | |
52 | if (!ring) | |
53 | return NULL; | |
54 | ||
75d0a7f3 CW |
55 | kref_init(&ring->ref); |
56 | ring->size = sz; | |
57 | ring->effective_size = sz; | |
58 | ring->vaddr = (void *)(ring + 1); | |
59 | atomic_set(&ring->pin_count, 1); | |
209760b7 | 60 | |
75d0a7f3 | 61 | intel_ring_update_space(ring); |
209760b7 | 62 | |
75d0a7f3 | 63 | return ring; |
209760b7 CW |
64 | } |
65 | ||
32eb6bcf | 66 | static struct i915_request *first_request(struct mock_engine *engine) |
f97fbf96 | 67 | { |
0daf0113 | 68 | return list_first_entry_or_null(&engine->hw_queue, |
32eb6bcf CW |
69 | struct i915_request, |
70 | mock.link); | |
0daf0113 CW |
71 | } |
72 | ||
32eb6bcf | 73 | static void advance(struct i915_request *request) |
b1f9107e | 74 | { |
32eb6bcf CW |
75 | list_del_init(&request->mock.link); |
76 | i915_request_mark_complete(request); | |
77 | GEM_BUG_ON(!i915_request_completed(request)); | |
52c0fdb2 | 78 | |
32eb6bcf | 79 | intel_engine_queue_breadcrumbs(request->engine); |
b1f9107e CW |
80 | } |
81 | ||
39cbf2aa | 82 | static void hw_delay_complete(struct timer_list *t) |
0daf0113 | 83 | { |
39cbf2aa | 84 | struct mock_engine *engine = from_timer(engine, t, hw_delay); |
32eb6bcf | 85 | struct i915_request *request; |
52c0fdb2 | 86 | unsigned long flags; |
0daf0113 | 87 | |
52c0fdb2 | 88 | spin_lock_irqsave(&engine->hw_lock, flags); |
0daf0113 | 89 | |
b1f9107e | 90 | /* Timer fired, first request is complete */ |
0daf0113 CW |
91 | request = first_request(engine); |
92 | if (request) | |
1579ab2d | 93 | advance(request); |
b1f9107e CW |
94 | |
95 | /* | |
96 | * Also immediately signal any subsequent 0-delay requests, but | |
97 | * requeue the timer for the next delayed request. | |
98 | */ | |
99 | while ((request = first_request(engine))) { | |
32eb6bcf CW |
100 | if (request->mock.delay) { |
101 | mod_timer(&engine->hw_delay, | |
102 | jiffies + request->mock.delay); | |
b1f9107e CW |
103 | break; |
104 | } | |
105 | ||
1579ab2d | 106 | advance(request); |
b1f9107e | 107 | } |
0daf0113 | 108 | |
52c0fdb2 | 109 | spin_unlock_irqrestore(&engine->hw_lock, flags); |
0daf0113 CW |
110 | } |
111 | ||
1fc44d9b | 112 | static void mock_context_unpin(struct intel_context *ce) |
0daf0113 | 113 | { |
1fc44d9b | 114 | } |
ab82a063 | 115 | |
4c5896dc | 116 | static void mock_context_destroy(struct kref *ref) |
1fc44d9b | 117 | { |
4c5896dc CW |
118 | struct intel_context *ce = container_of(ref, typeof(*ce), ref); |
119 | ||
08819549 | 120 | GEM_BUG_ON(intel_context_is_pinned(ce)); |
209760b7 | 121 | |
75d0a7f3 CW |
122 | if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { |
123 | kfree(ce->ring); | |
124 | mock_timeline_unpin(ce->timeline); | |
125 | } | |
4c5896dc | 126 | |
df8cf31e | 127 | intel_context_fini(ce); |
4c5896dc | 128 | intel_context_free(ce); |
0daf0113 CW |
129 | } |
130 | ||
4c60b1aa CW |
131 | static int mock_context_alloc(struct intel_context *ce) |
132 | { | |
133 | ce->ring = mock_ring(ce->engine); | |
134 | if (!ce->ring) | |
135 | return -ENOMEM; | |
136 | ||
75d0a7f3 CW |
137 | GEM_BUG_ON(ce->timeline); |
138 | ce->timeline = intel_timeline_create(ce->engine->gt, NULL); | |
139 | if (IS_ERR(ce->timeline)) { | |
140 | kfree(ce->engine); | |
141 | return PTR_ERR(ce->timeline); | |
142 | } | |
143 | ||
144 | mock_timeline_pin(ce->timeline); | |
145 | ||
4c60b1aa CW |
146 | return 0; |
147 | } | |
148 | ||
95f697eb | 149 | static int mock_context_pin(struct intel_context *ce) |
0daf0113 | 150 | { |
75d0a7f3 | 151 | return intel_context_active_acquire(ce); |
0daf0113 CW |
152 | } |
153 | ||
4dc84b77 | 154 | static const struct intel_context_ops mock_context_ops = { |
4c60b1aa CW |
155 | .alloc = mock_context_alloc, |
156 | ||
95f697eb | 157 | .pin = mock_context_pin, |
4dc84b77 | 158 | .unpin = mock_context_unpin, |
4c5896dc | 159 | |
6eee33e8 CW |
160 | .enter = intel_context_enter_engine, |
161 | .exit = intel_context_exit_engine, | |
162 | ||
4dc84b77 CW |
163 | .destroy = mock_context_destroy, |
164 | }; | |
165 | ||
e61e0f51 | 166 | static int mock_request_alloc(struct i915_request *request) |
0daf0113 | 167 | { |
32eb6bcf CW |
168 | INIT_LIST_HEAD(&request->mock.link); |
169 | request->mock.delay = 0; | |
0daf0113 | 170 | |
0daf0113 CW |
171 | return 0; |
172 | } | |
173 | ||
e61e0f51 | 174 | static int mock_emit_flush(struct i915_request *request, |
0daf0113 CW |
175 | unsigned int flags) |
176 | { | |
177 | return 0; | |
178 | } | |
179 | ||
e1a73a54 | 180 | static u32 *mock_emit_breadcrumb(struct i915_request *request, u32 *cs) |
0daf0113 | 181 | { |
e1a73a54 | 182 | return cs; |
0daf0113 CW |
183 | } |
184 | ||
e61e0f51 | 185 | static void mock_submit_request(struct i915_request *request) |
0daf0113 | 186 | { |
0daf0113 CW |
187 | struct mock_engine *engine = |
188 | container_of(request->engine, typeof(*engine), base); | |
52c0fdb2 | 189 | unsigned long flags; |
0daf0113 | 190 | |
e61e0f51 | 191 | i915_request_submit(request); |
0daf0113 | 192 | |
52c0fdb2 | 193 | spin_lock_irqsave(&engine->hw_lock, flags); |
32eb6bcf CW |
194 | list_add_tail(&request->mock.link, &engine->hw_queue); |
195 | if (list_is_first(&request->mock.link, &engine->hw_queue)) { | |
196 | if (request->mock.delay) | |
197 | mod_timer(&engine->hw_delay, | |
198 | jiffies + request->mock.delay); | |
b1f9107e | 199 | else |
32eb6bcf | 200 | advance(request); |
b1f9107e | 201 | } |
52c0fdb2 | 202 | spin_unlock_irqrestore(&engine->hw_lock, flags); |
0daf0113 CW |
203 | } |
204 | ||
d315d4fa CW |
205 | static void mock_reset_prepare(struct intel_engine_cs *engine) |
206 | { | |
207 | } | |
208 | ||
209 | static void mock_reset(struct intel_engine_cs *engine, bool stalled) | |
210 | { | |
211 | GEM_BUG_ON(stalled); | |
212 | } | |
213 | ||
214 | static void mock_reset_finish(struct intel_engine_cs *engine) | |
215 | { | |
216 | } | |
217 | ||
218 | static void mock_cancel_requests(struct intel_engine_cs *engine) | |
219 | { | |
220 | struct i915_request *request; | |
221 | unsigned long flags; | |
222 | ||
422d7df4 | 223 | spin_lock_irqsave(&engine->active.lock, flags); |
d315d4fa CW |
224 | |
225 | /* Mark all submitted requests as skipped. */ | |
422d7df4 | 226 | list_for_each_entry(request, &engine->active.requests, sched.link) { |
d315d4fa CW |
227 | if (!i915_request_signaled(request)) |
228 | dma_fence_set_error(&request->fence, -EIO); | |
229 | ||
230 | i915_request_mark_complete(request); | |
231 | } | |
232 | ||
422d7df4 | 233 | spin_unlock_irqrestore(&engine->active.lock, flags); |
d315d4fa CW |
234 | } |
235 | ||
0daf0113 | 236 | struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, |
3ec0af7f CW |
237 | const char *name, |
238 | int id) | |
0daf0113 CW |
239 | { |
240 | struct mock_engine *engine; | |
3ec0af7f CW |
241 | |
242 | GEM_BUG_ON(id >= I915_NUM_ENGINES); | |
d14a701b | 243 | GEM_BUG_ON(!i915->gt.uncore); |
f97fbf96 CW |
244 | |
245 | engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL); | |
246 | if (!engine) | |
247 | return NULL; | |
248 | ||
0daf0113 CW |
249 | /* minimal engine setup for requests */ |
250 | engine->base.i915 = i915; | |
f937f561 | 251 | engine->base.gt = &i915->gt; |
3de16278 | 252 | engine->base.uncore = i915->gt.uncore; |
6e516148 | 253 | snprintf(engine->base.name, sizeof(engine->base.name), "%s", name); |
3ec0af7f | 254 | engine->base.id = id; |
8a68d464 | 255 | engine->base.mask = BIT(id); |
cbb153c5 | 256 | engine->base.instance = id; |
0ca88ba0 | 257 | engine->base.status_page.addr = (void *)(engine + 1); |
f97fbf96 | 258 | |
4dc84b77 | 259 | engine->base.cops = &mock_context_ops; |
0daf0113 CW |
260 | engine->base.request_alloc = mock_request_alloc; |
261 | engine->base.emit_flush = mock_emit_flush; | |
85474441 | 262 | engine->base.emit_fini_breadcrumb = mock_emit_breadcrumb; |
0daf0113 CW |
263 | engine->base.submit_request = mock_submit_request; |
264 | ||
d315d4fa CW |
265 | engine->base.reset.prepare = mock_reset_prepare; |
266 | engine->base.reset.reset = mock_reset; | |
267 | engine->base.reset.finish = mock_reset_finish; | |
268 | engine->base.cancel_requests = mock_cancel_requests; | |
269 | ||
0daf0113 CW |
270 | /* fake hw queue */ |
271 | spin_lock_init(&engine->hw_lock); | |
39cbf2aa | 272 | timer_setup(&engine->hw_delay, hw_delay_complete, 0); |
0daf0113 CW |
273 | INIT_LIST_HEAD(&engine->hw_queue); |
274 | ||
cbb153c5 CW |
275 | intel_engine_add_user(&engine->base); |
276 | ||
11334c6a CW |
277 | return &engine->base; |
278 | } | |
279 | ||
280 | int mock_engine_init(struct intel_engine_cs *engine) | |
281 | { | |
38775829 | 282 | struct intel_context *ce; |
11334c6a | 283 | |
422d7df4 | 284 | intel_engine_init_active(engine, ENGINE_MOCK); |
11334c6a CW |
285 | intel_engine_init_breadcrumbs(engine); |
286 | intel_engine_init_execlists(engine); | |
287 | intel_engine_init__pm(engine); | |
b40d7378 | 288 | intel_engine_pool_init(&engine->pool); |
11334c6a | 289 | |
38775829 CW |
290 | ce = create_kernel_context(engine); |
291 | if (IS_ERR(ce)) | |
422d7df4 | 292 | goto err_breadcrumbs; |
fa9f6681 | 293 | |
38775829 | 294 | engine->kernel_context = ce; |
11334c6a | 295 | return 0; |
b887d615 CW |
296 | |
297 | err_breadcrumbs: | |
11334c6a CW |
298 | intel_engine_fini_breadcrumbs(engine); |
299 | return -ENOMEM; | |
f97fbf96 CW |
300 | } |
301 | ||
302 | void mock_engine_flush(struct intel_engine_cs *engine) | |
303 | { | |
0daf0113 CW |
304 | struct mock_engine *mock = |
305 | container_of(engine, typeof(*mock), base); | |
32eb6bcf | 306 | struct i915_request *request, *rn; |
0daf0113 CW |
307 | |
308 | del_timer_sync(&mock->hw_delay); | |
309 | ||
310 | spin_lock_irq(&mock->hw_lock); | |
32eb6bcf | 311 | list_for_each_entry_safe(request, rn, &mock->hw_queue, mock.link) |
1579ab2d | 312 | advance(request); |
0daf0113 | 313 | spin_unlock_irq(&mock->hw_lock); |
f97fbf96 CW |
314 | } |
315 | ||
316 | void mock_engine_reset(struct intel_engine_cs *engine) | |
317 | { | |
f97fbf96 | 318 | } |
0daf0113 CW |
319 | |
320 | void mock_engine_free(struct intel_engine_cs *engine) | |
321 | { | |
322 | struct mock_engine *mock = | |
323 | container_of(engine, typeof(*mock), base); | |
324 | ||
325 | GEM_BUG_ON(timer_pending(&mock->hw_delay)); | |
326 | ||
9dbfea98 | 327 | intel_context_unpin(engine->kernel_context); |
38775829 | 328 | intel_context_put(engine->kernel_context); |
4a774ee3 | 329 | |
0daf0113 CW |
330 | intel_engine_fini_breadcrumbs(engine); |
331 | ||
0daf0113 CW |
332 | kfree(engine); |
333 | } |