]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/gpu/drm/i915/selftests/mock_engine.c
Merge branch 'drm-next-5.1' of git://people.freedesktop.org/~agd5f/linux into drm...
[thirdparty/kernel/stable.git] / drivers / gpu / drm / i915 / selftests / mock_engine.c
CommitLineData
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
25#include "mock_engine.h"
0daf0113 26#include "mock_request.h"
f97fbf96 27
a89d1f92
CW
28struct mock_ring {
29 struct intel_ring base;
30 struct i915_timeline timeline;
31};
32
5013eb8c
CW
33static void mock_timeline_pin(struct i915_timeline *tl)
34{
35 tl->pin_count++;
36}
37
38static void mock_timeline_unpin(struct i915_timeline *tl)
39{
40 GEM_BUG_ON(!tl->pin_count);
41 tl->pin_count--;
42}
43
209760b7
CW
44static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
45{
46 const unsigned long sz = PAGE_SIZE / 2;
47 struct mock_ring *ring;
48
49 ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL);
50 if (!ring)
51 return NULL;
52
52954edd
CW
53 if (i915_timeline_init(engine->i915,
54 &ring->timeline, engine->name,
55 NULL)) {
56 kfree(ring);
57 return NULL;
58 }
209760b7
CW
59
60 ring->base.size = sz;
61 ring->base.effective_size = sz;
62 ring->base.vaddr = (void *)(ring + 1);
63 ring->base.timeline = &ring->timeline;
64
65 INIT_LIST_HEAD(&ring->base.request_list);
66 intel_ring_update_space(&ring->base);
67
68 return &ring->base;
69}
70
71static void mock_ring_free(struct intel_ring *base)
72{
73 struct mock_ring *ring = container_of(base, typeof(*ring), base);
74
75 i915_timeline_fini(&ring->timeline);
76 kfree(ring);
77}
78
0daf0113 79static struct mock_request *first_request(struct mock_engine *engine)
f97fbf96 80{
0daf0113
CW
81 return list_first_entry_or_null(&engine->hw_queue,
82 struct mock_request,
83 link);
84}
85
1579ab2d 86static void advance(struct mock_request *request)
b1f9107e
CW
87{
88 list_del_init(&request->link);
52c0fdb2
CW
89 intel_engine_write_global_seqno(request->base.engine,
90 request->base.global_seqno);
5013eb8c
CW
91 i915_request_mark_complete(&request->base);
92 GEM_BUG_ON(!i915_request_completed(&request->base));
52c0fdb2
CW
93
94 intel_engine_queue_breadcrumbs(request->base.engine);
b1f9107e
CW
95}
96
39cbf2aa 97static void hw_delay_complete(struct timer_list *t)
0daf0113 98{
39cbf2aa 99 struct mock_engine *engine = from_timer(engine, t, hw_delay);
0daf0113 100 struct mock_request *request;
52c0fdb2 101 unsigned long flags;
0daf0113 102
52c0fdb2 103 spin_lock_irqsave(&engine->hw_lock, flags);
0daf0113 104
b1f9107e 105 /* Timer fired, first request is complete */
0daf0113
CW
106 request = first_request(engine);
107 if (request)
1579ab2d 108 advance(request);
b1f9107e
CW
109
110 /*
111 * Also immediately signal any subsequent 0-delay requests, but
112 * requeue the timer for the next delayed request.
113 */
114 while ((request = first_request(engine))) {
115 if (request->delay) {
116 mod_timer(&engine->hw_delay, jiffies + request->delay);
117 break;
118 }
119
1579ab2d 120 advance(request);
b1f9107e 121 }
0daf0113 122
52c0fdb2 123 spin_unlock_irqrestore(&engine->hw_lock, flags);
0daf0113
CW
124}
125
1fc44d9b 126static void mock_context_unpin(struct intel_context *ce)
0daf0113 127{
5013eb8c 128 mock_timeline_unpin(ce->ring->timeline);
1fc44d9b
CW
129 i915_gem_context_put(ce->gem_context);
130}
ab82a063 131
1fc44d9b
CW
132static void mock_context_destroy(struct intel_context *ce)
133{
134 GEM_BUG_ON(ce->pin_count);
209760b7
CW
135
136 if (ce->ring)
137 mock_ring_free(ce->ring);
0daf0113
CW
138}
139
1fc44d9b
CW
140static const struct intel_context_ops mock_context_ops = {
141 .unpin = mock_context_unpin,
142 .destroy = mock_context_destroy,
143};
144
145static struct intel_context *
146mock_context_pin(struct intel_engine_cs *engine,
147 struct i915_gem_context *ctx)
0daf0113 148{
ab82a063 149 struct intel_context *ce = to_intel_context(ctx, engine);
5013eb8c 150 int err = -ENOMEM;
ab82a063 151
209760b7
CW
152 if (ce->pin_count++)
153 return ce;
154
155 if (!ce->ring) {
156 ce->ring = mock_ring(engine);
157 if (!ce->ring)
158 goto err;
1fc44d9b
CW
159 }
160
5013eb8c
CW
161 mock_timeline_pin(ce->ring->timeline);
162
209760b7
CW
163 ce->ops = &mock_context_ops;
164 i915_gem_context_get(ctx);
1fc44d9b 165 return ce;
209760b7
CW
166
167err:
168 ce->pin_count = 0;
5013eb8c 169 return ERR_PTR(err);
0daf0113
CW
170}
171
e61e0f51 172static int mock_request_alloc(struct i915_request *request)
0daf0113
CW
173{
174 struct mock_request *mock = container_of(request, typeof(*mock), base);
175
176 INIT_LIST_HEAD(&mock->link);
177 mock->delay = 0;
178
0daf0113
CW
179 return 0;
180}
181
e61e0f51 182static int mock_emit_flush(struct i915_request *request,
0daf0113
CW
183 unsigned int flags)
184{
185 return 0;
186}
187
e1a73a54 188static u32 *mock_emit_breadcrumb(struct i915_request *request, u32 *cs)
0daf0113 189{
e1a73a54 190 return cs;
0daf0113
CW
191}
192
e61e0f51 193static void mock_submit_request(struct i915_request *request)
0daf0113
CW
194{
195 struct mock_request *mock = container_of(request, typeof(*mock), base);
196 struct mock_engine *engine =
197 container_of(request->engine, typeof(*engine), base);
52c0fdb2 198 unsigned long flags;
0daf0113 199
e61e0f51 200 i915_request_submit(request);
0daf0113
CW
201 GEM_BUG_ON(!request->global_seqno);
202
52c0fdb2 203 spin_lock_irqsave(&engine->hw_lock, flags);
0daf0113 204 list_add_tail(&mock->link, &engine->hw_queue);
b1f9107e
CW
205 if (mock->link.prev == &engine->hw_queue) {
206 if (mock->delay)
207 mod_timer(&engine->hw_delay, jiffies + mock->delay);
208 else
1579ab2d 209 advance(mock);
b1f9107e 210 }
52c0fdb2 211 spin_unlock_irqrestore(&engine->hw_lock, flags);
0daf0113
CW
212}
213
0daf0113 214struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
3ec0af7f
CW
215 const char *name,
216 int id)
0daf0113
CW
217{
218 struct mock_engine *engine;
3ec0af7f
CW
219
220 GEM_BUG_ON(id >= I915_NUM_ENGINES);
f97fbf96
CW
221
222 engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL);
223 if (!engine)
224 return NULL;
225
0daf0113
CW
226 /* minimal engine setup for requests */
227 engine->base.i915 = i915;
6e516148 228 snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
3ec0af7f 229 engine->base.id = id;
0ca88ba0 230 engine->base.status_page.addr = (void *)(engine + 1);
f97fbf96 231
0daf0113 232 engine->base.context_pin = mock_context_pin;
0daf0113
CW
233 engine->base.request_alloc = mock_request_alloc;
234 engine->base.emit_flush = mock_emit_flush;
85474441 235 engine->base.emit_fini_breadcrumb = mock_emit_breadcrumb;
0daf0113
CW
236 engine->base.submit_request = mock_submit_request;
237
52954edd
CW
238 if (i915_timeline_init(i915,
239 &engine->base.timeline,
240 engine->base.name,
241 NULL))
242 goto err_free;
f911e723 243 i915_timeline_set_subclass(&engine->base.timeline, TIMELINE_ENGINE);
890fd185 244
0daf0113 245 intel_engine_init_breadcrumbs(&engine->base);
0daf0113
CW
246
247 /* fake hw queue */
248 spin_lock_init(&engine->hw_lock);
39cbf2aa 249 timer_setup(&engine->hw_delay, hw_delay_complete, 0);
0daf0113
CW
250 INIT_LIST_HEAD(&engine->hw_queue);
251
4a774ee3 252 if (IS_ERR(intel_context_pin(i915->kernel_context, &engine->base)))
209760b7 253 goto err_breadcrumbs;
4a774ee3 254
0daf0113 255 return &engine->base;
b887d615
CW
256
257err_breadcrumbs:
258 intel_engine_fini_breadcrumbs(&engine->base);
a89d1f92 259 i915_timeline_fini(&engine->base.timeline);
52954edd 260err_free:
b887d615
CW
261 kfree(engine);
262 return NULL;
f97fbf96
CW
263}
264
265void mock_engine_flush(struct intel_engine_cs *engine)
266{
0daf0113
CW
267 struct mock_engine *mock =
268 container_of(engine, typeof(*mock), base);
269 struct mock_request *request, *rn;
270
271 del_timer_sync(&mock->hw_delay);
272
273 spin_lock_irq(&mock->hw_lock);
1579ab2d
CW
274 list_for_each_entry_safe(request, rn, &mock->hw_queue, link)
275 advance(request);
0daf0113 276 spin_unlock_irq(&mock->hw_lock);
f97fbf96
CW
277}
278
279void mock_engine_reset(struct intel_engine_cs *engine)
280{
52c0fdb2 281 intel_engine_write_global_seqno(engine, 0);
f97fbf96 282}
0daf0113
CW
283
284void mock_engine_free(struct intel_engine_cs *engine)
285{
286 struct mock_engine *mock =
287 container_of(engine, typeof(*mock), base);
1fc44d9b 288 struct intel_context *ce;
0daf0113
CW
289
290 GEM_BUG_ON(timer_pending(&mock->hw_delay));
291
1fc44d9b
CW
292 ce = fetch_and_zero(&engine->last_retired_context);
293 if (ce)
294 intel_context_unpin(ce);
0daf0113 295
4a774ee3
CW
296 __intel_context_unpin(engine->i915->kernel_context, engine);
297
0daf0113 298 intel_engine_fini_breadcrumbs(engine);
a89d1f92 299 i915_timeline_fini(&engine->timeline);
0daf0113 300
0daf0113
CW
301 kfree(engine);
302}