drm/i915: Move context management under GEM
[linux-block.git] / drivers / gpu / drm / i915 / gem / selftests / i915_gem_context.c
CommitLineData
791ff39a 1/*
10be98a7 2 * SPDX-License-Identifier: MIT
791ff39a 3 *
10be98a7 4 * Copyright © 2017 Intel Corporation
791ff39a
CW
5 */
6
a47cd45a
CW
7#include <linux/prime_numbers.h>
8
10be98a7 9#include "gem/i915_gem_pm.h"
cb823ed9 10#include "gt/intel_gt.h"
66101975 11#include "gt/intel_gt_requests.h"
112ed2d3
CW
12#include "gt/intel_reset.h"
13#include "i915_selftest.h"
14
10be98a7
CW
15#include "gem/selftests/igt_gem_utils.h"
16#include "selftests/i915_random.h"
17#include "selftests/igt_flush_test.h"
18#include "selftests/igt_live_test.h"
19#include "selftests/igt_reset.h"
20#include "selftests/igt_spinner.h"
21#include "selftests/mock_drm.h"
22#include "selftests/mock_gem_device.h"
791ff39a 23
791ff39a 24#include "huge_gem_object.h"
10be98a7 25#include "igt_gem_utils.h"
791ff39a
CW
26
27#define DW_PER_PAGE (PAGE_SIZE / sizeof(u32))
28
a47cd45a
CW
29static int live_nop_switch(void *arg)
30{
31 const unsigned int nctx = 1024;
32 struct drm_i915_private *i915 = arg;
33 struct intel_engine_cs *engine;
34 struct i915_gem_context **ctx;
35 enum intel_engine_id id;
e4a8c813 36 struct igt_live_test t;
a47cd45a 37 struct drm_file *file;
a47cd45a
CW
38 unsigned long n;
39 int err = -ENODEV;
40
41 /*
42 * Create as many contexts as we can feasibly get away with
43 * and check we can switch between them rapidly.
44 *
45 * Serves as very simple stress test for submission and HW switching
46 * between contexts.
47 */
48
49 if (!DRIVER_CAPS(i915)->has_logical_contexts)
50 return 0;
51
52 file = mock_file(i915);
53 if (IS_ERR(file))
54 return PTR_ERR(file);
55
a47cd45a
CW
56 ctx = kcalloc(nctx, sizeof(*ctx), GFP_KERNEL);
57 if (!ctx) {
58 err = -ENOMEM;
a4e7ccda 59 goto out_file;
a47cd45a
CW
60 }
61
62 for (n = 0; n < nctx; n++) {
3aa9945a 63 ctx[n] = live_context(i915, file);
a47cd45a
CW
64 if (IS_ERR(ctx[n])) {
65 err = PTR_ERR(ctx[n]);
a4e7ccda 66 goto out_file;
a47cd45a
CW
67 }
68 }
69
70 for_each_engine(engine, i915, id) {
71 struct i915_request *rq;
72 unsigned long end_time, prime;
73 ktime_t times[2] = {};
74
75 times[0] = ktime_get_raw();
76 for (n = 0; n < nctx; n++) {
46472b3e 77 rq = igt_request_alloc(ctx[n], engine);
a47cd45a
CW
78 if (IS_ERR(rq)) {
79 err = PTR_ERR(rq);
a4e7ccda 80 goto out_file;
a47cd45a
CW
81 }
82 i915_request_add(rq);
83 }
2f530945 84 if (i915_request_wait(rq, 0, HZ / 5) < 0) {
a47cd45a 85 pr_err("Failed to populated %d contexts\n", nctx);
cb823ed9 86 intel_gt_set_wedged(&i915->gt);
a47cd45a 87 err = -EIO;
a4e7ccda 88 goto out_file;
a47cd45a
CW
89 }
90
91 times[1] = ktime_get_raw();
92
93 pr_info("Populated %d contexts on %s in %lluns\n",
94 nctx, engine->name, ktime_to_ns(times[1] - times[0]));
95
e4a8c813 96 err = igt_live_test_begin(&t, i915, __func__, engine->name);
a47cd45a 97 if (err)
a4e7ccda 98 goto out_file;
a47cd45a
CW
99
100 end_time = jiffies + i915_selftest.timeout_jiffies;
101 for_each_prime_number_from(prime, 2, 8192) {
102 times[1] = ktime_get_raw();
103
104 for (n = 0; n < prime; n++) {
46472b3e 105 rq = igt_request_alloc(ctx[n % nctx], engine);
a47cd45a
CW
106 if (IS_ERR(rq)) {
107 err = PTR_ERR(rq);
a4e7ccda 108 goto out_file;
a47cd45a
CW
109 }
110
111 /*
112 * This space is left intentionally blank.
113 *
114 * We do not actually want to perform any
115 * action with this request, we just want
116 * to measure the latency in allocation
117 * and submission of our breadcrumbs -
118 * ensuring that the bare request is sufficient
119 * for the system to work (i.e. proper HEAD
120 * tracking of the rings, interrupt handling,
121 * etc). It also gives us the lowest bounds
122 * for latency.
123 */
124
125 i915_request_add(rq);
126 }
2f530945 127 if (i915_request_wait(rq, 0, HZ / 5) < 0) {
a47cd45a
CW
128 pr_err("Switching between %ld contexts timed out\n",
129 prime);
cb823ed9 130 intel_gt_set_wedged(&i915->gt);
a47cd45a
CW
131 break;
132 }
133
134 times[1] = ktime_sub(ktime_get_raw(), times[1]);
135 if (prime == 2)
136 times[0] = times[1];
137
138 if (__igt_timeout(end_time, NULL))
139 break;
140 }
141
e4a8c813 142 err = igt_live_test_end(&t);
a47cd45a 143 if (err)
a4e7ccda 144 goto out_file;
a47cd45a
CW
145
146 pr_info("Switch latencies on %s: 1 = %lluns, %lu = %lluns\n",
147 engine->name,
148 ktime_to_ns(times[0]),
149 prime - 1, div64_u64(ktime_to_ns(times[1]), prime - 1));
150 }
151
a4e7ccda 152out_file:
a47cd45a
CW
153 mock_file_free(i915, file);
154 return err;
155}
156
50d16d44
CW
157struct parallel_switch {
158 struct task_struct *tsk;
159 struct intel_context *ce[2];
160};
161
162static int __live_parallel_switch1(void *data)
163{
164 struct parallel_switch *arg = data;
50d16d44
CW
165 IGT_TIMEOUT(end_time);
166 unsigned long count;
167
168 count = 0;
169 do {
170 struct i915_request *rq = NULL;
171 int err, n;
172
173 for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
174 i915_request_put(rq);
175
50d16d44 176 rq = i915_request_create(arg->ce[n]);
7e805762 177 if (IS_ERR(rq))
50d16d44 178 return PTR_ERR(rq);
50d16d44
CW
179
180 i915_request_get(rq);
181 i915_request_add(rq);
50d16d44
CW
182 }
183
184 err = 0;
185 if (i915_request_wait(rq, 0, HZ / 5) < 0)
186 err = -ETIME;
187 i915_request_put(rq);
188 if (err)
189 return err;
190
191 count++;
192 } while (!__igt_timeout(end_time, NULL));
193
194 pr_info("%s: %lu switches (sync)\n", arg->ce[0]->engine->name, count);
195 return 0;
196}
197
198static int __live_parallel_switchN(void *data)
199{
200 struct parallel_switch *arg = data;
50d16d44
CW
201 IGT_TIMEOUT(end_time);
202 unsigned long count;
203 int n;
204
205 count = 0;
206 do {
207 for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
208 struct i915_request *rq;
209
50d16d44 210 rq = i915_request_create(arg->ce[n]);
7e805762 211 if (IS_ERR(rq))
50d16d44 212 return PTR_ERR(rq);
50d16d44
CW
213
214 i915_request_add(rq);
50d16d44
CW
215 }
216
217 count++;
218 } while (!__igt_timeout(end_time, NULL));
219
220 pr_info("%s: %lu switches (many)\n", arg->ce[0]->engine->name, count);
221 return 0;
222}
223
224static int live_parallel_switch(void *arg)
225{
226 struct drm_i915_private *i915 = arg;
227 static int (* const func[])(void *arg) = {
228 __live_parallel_switch1,
229 __live_parallel_switchN,
230 NULL,
231 };
232 struct parallel_switch *data = NULL;
233 struct i915_gem_engines *engines;
234 struct i915_gem_engines_iter it;
235 int (* const *fn)(void *arg);
236 struct i915_gem_context *ctx;
237 struct intel_context *ce;
238 struct drm_file *file;
239 int n, m, count;
240 int err = 0;
241
242 /*
243 * Check we can process switches on all engines simultaneously.
244 */
245
246 if (!DRIVER_CAPS(i915)->has_logical_contexts)
247 return 0;
248
249 file = mock_file(i915);
250 if (IS_ERR(file))
251 return PTR_ERR(file);
252
50d16d44
CW
253 ctx = live_context(i915, file);
254 if (IS_ERR(ctx)) {
255 err = PTR_ERR(ctx);
a4e7ccda 256 goto out_file;
50d16d44
CW
257 }
258
259 engines = i915_gem_context_lock_engines(ctx);
260 count = engines->num_engines;
261
262 data = kcalloc(count, sizeof(*data), GFP_KERNEL);
263 if (!data) {
264 i915_gem_context_unlock_engines(ctx);
265 err = -ENOMEM;
a4e7ccda 266 goto out;
50d16d44
CW
267 }
268
269 m = 0; /* Use the first context as our template for the engines */
270 for_each_gem_engine(ce, engines, it) {
271 err = intel_context_pin(ce);
272 if (err) {
273 i915_gem_context_unlock_engines(ctx);
a4e7ccda 274 goto out;
50d16d44
CW
275 }
276 data[m++].ce[0] = intel_context_get(ce);
277 }
278 i915_gem_context_unlock_engines(ctx);
279
280 /* Clone the same set of engines into the other contexts */
281 for (n = 1; n < ARRAY_SIZE(data->ce); n++) {
282 ctx = live_context(i915, file);
283 if (IS_ERR(ctx)) {
284 err = PTR_ERR(ctx);
a4e7ccda 285 goto out;
50d16d44
CW
286 }
287
288 for (m = 0; m < count; m++) {
289 if (!data[m].ce[0])
290 continue;
291
292 ce = intel_context_create(ctx, data[m].ce[0]->engine);
293 if (IS_ERR(ce))
a4e7ccda 294 goto out;
50d16d44
CW
295
296 err = intel_context_pin(ce);
297 if (err) {
298 intel_context_put(ce);
a4e7ccda 299 goto out;
50d16d44
CW
300 }
301
302 data[m].ce[n] = ce;
303 }
304 }
305
50d16d44
CW
306 for (fn = func; !err && *fn; fn++) {
307 struct igt_live_test t;
308 int n;
309
310 mutex_lock(&i915->drm.struct_mutex);
311 err = igt_live_test_begin(&t, i915, __func__, "");
312 mutex_unlock(&i915->drm.struct_mutex);
313 if (err)
314 break;
315
316 for (n = 0; n < count; n++) {
317 if (!data[n].ce[0])
318 continue;
319
320 data[n].tsk = kthread_run(*fn, &data[n],
321 "igt/parallel:%s",
322 data[n].ce[0]->engine->name);
323 if (IS_ERR(data[n].tsk)) {
324 err = PTR_ERR(data[n].tsk);
325 break;
326 }
327 get_task_struct(data[n].tsk);
328 }
329
330 for (n = 0; n < count; n++) {
331 int status;
332
333 if (IS_ERR_OR_NULL(data[n].tsk))
334 continue;
335
336 status = kthread_stop(data[n].tsk);
337 if (status && !err)
338 err = status;
339
340 put_task_struct(data[n].tsk);
341 data[n].tsk = NULL;
342 }
343
344 mutex_lock(&i915->drm.struct_mutex);
345 if (igt_live_test_end(&t))
346 err = -EIO;
347 mutex_unlock(&i915->drm.struct_mutex);
348 }
349
a4e7ccda 350out:
50d16d44
CW
351 for (n = 0; n < count; n++) {
352 for (m = 0; m < ARRAY_SIZE(data->ce); m++) {
353 if (!data[n].ce[m])
354 continue;
355
356 intel_context_unpin(data[n].ce[m]);
357 intel_context_put(data[n].ce[m]);
358 }
359 }
50d16d44 360 kfree(data);
a4e7ccda 361out_file:
50d16d44
CW
362 mock_file_free(i915, file);
363 return err;
364}
365
791ff39a
CW
366static unsigned long real_page_count(struct drm_i915_gem_object *obj)
367{
368 return huge_gem_object_phys_size(obj) >> PAGE_SHIFT;
369}
370
371static unsigned long fake_page_count(struct drm_i915_gem_object *obj)
372{
373 return huge_gem_object_dma_size(obj) >> PAGE_SHIFT;
374}
375
75b974a8
CW
376static int gpu_fill(struct intel_context *ce,
377 struct drm_i915_gem_object *obj,
791ff39a
CW
378 unsigned int dw)
379{
791ff39a 380 struct i915_vma *vma;
791ff39a
CW
381 int err;
382
75b974a8
CW
383 GEM_BUG_ON(obj->base.size > ce->vm->total);
384 GEM_BUG_ON(!intel_engine_can_store_dword(ce->engine));
791ff39a 385
75b974a8 386 vma = i915_vma_instance(obj, ce->vm, NULL);
791ff39a
CW
387 if (IS_ERR(vma))
388 return PTR_ERR(vma);
389
791ff39a
CW
390 err = i915_vma_pin(vma, 0, 0, PIN_HIGH | PIN_USER);
391 if (err)
392 return err;
393
18851edf
MA
394 /*
395 * Within the GTT the huge objects maps every page onto
791ff39a
CW
396 * its 1024 real pages (using phys_pfn = dma_pfn % 1024).
397 * We set the nth dword within the page using the nth
398 * mapping via the GTT - this should exercise the GTT mapping
399 * whilst checking that each context provides a unique view
400 * into the object.
401 */
75b974a8 402 err = igt_gpu_fill_dw(ce, vma,
18851edf
MA
403 (dw * real_page_count(obj)) << PAGE_SHIFT |
404 (dw * sizeof(u32)),
405 real_page_count(obj),
406 dw);
791ff39a
CW
407 i915_vma_unpin(vma);
408
791ff39a
CW
409 return err;
410}
411
412static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
413{
414 const bool has_llc = HAS_LLC(to_i915(obj->base.dev));
415 unsigned int n, m, need_flush;
416 int err;
417
f0e4a063 418 err = i915_gem_object_prepare_write(obj, &need_flush);
791ff39a
CW
419 if (err)
420 return err;
421
422 for (n = 0; n < real_page_count(obj); n++) {
423 u32 *map;
424
425 map = kmap_atomic(i915_gem_object_get_page(obj, n));
426 for (m = 0; m < DW_PER_PAGE; m++)
427 map[m] = value;
428 if (!has_llc)
429 drm_clflush_virt_range(map, PAGE_SIZE);
430 kunmap_atomic(map);
431 }
432
f0e4a063 433 i915_gem_object_finish_access(obj);
c0a51fd0
CK
434 obj->read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
435 obj->write_domain = 0;
791ff39a
CW
436 return 0;
437}
438
e0695db7
CW
439static noinline int cpu_check(struct drm_i915_gem_object *obj,
440 unsigned int idx, unsigned int max)
791ff39a
CW
441{
442 unsigned int n, m, needs_flush;
443 int err;
444
f0e4a063 445 err = i915_gem_object_prepare_read(obj, &needs_flush);
791ff39a
CW
446 if (err)
447 return err;
448
449 for (n = 0; n < real_page_count(obj); n++) {
450 u32 *map;
451
452 map = kmap_atomic(i915_gem_object_get_page(obj, n));
453 if (needs_flush & CLFLUSH_BEFORE)
454 drm_clflush_virt_range(map, PAGE_SIZE);
455
456 for (m = 0; m < max; m++) {
457 if (map[m] != m) {
e0695db7
CW
458 pr_err("%pS: Invalid value at object %d page %d/%ld, offset %d/%d: found %x expected %x\n",
459 __builtin_return_address(0), idx,
460 n, real_page_count(obj), m, max,
461 map[m], m);
791ff39a
CW
462 err = -EINVAL;
463 goto out_unmap;
464 }
465 }
466
467 for (; m < DW_PER_PAGE; m++) {
250f8c81 468 if (map[m] != STACK_MAGIC) {
e0695db7
CW
469 pr_err("%pS: Invalid value at object %d page %d, offset %d: found %x expected %x (uninitialised)\n",
470 __builtin_return_address(0), idx, n, m,
471 map[m], STACK_MAGIC);
791ff39a
CW
472 err = -EINVAL;
473 goto out_unmap;
474 }
475 }
476
477out_unmap:
478 kunmap_atomic(map);
479 if (err)
480 break;
481 }
482
f0e4a063 483 i915_gem_object_finish_access(obj);
791ff39a
CW
484 return err;
485}
486
f9eb63b9
CW
487static int file_add_object(struct drm_file *file,
488 struct drm_i915_gem_object *obj)
489{
490 int err;
491
492 GEM_BUG_ON(obj->base.handle_count);
493
494 /* tie the object to the drm_file for easy reaping */
495 err = idr_alloc(&file->object_idr, &obj->base, 1, 0, GFP_KERNEL);
496 if (err < 0)
497 return err;
498
499 i915_gem_object_get(obj);
500 obj->base.handle_count++;
501 return 0;
502}
503
791ff39a 504static struct drm_i915_gem_object *
75b974a8 505create_test_object(struct i915_address_space *vm,
791ff39a
CW
506 struct drm_file *file,
507 struct list_head *objects)
508{
509 struct drm_i915_gem_object *obj;
791ff39a 510 u64 size;
791ff39a
CW
511 int err;
512
9e953980 513 /* Keep in GEM's good graces */
66101975 514 intel_gt_retire_requests(vm->gt);
9e953980 515
791ff39a
CW
516 size = min(vm->total / 2, 1024ull * DW_PER_PAGE * PAGE_SIZE);
517 size = round_down(size, DW_PER_PAGE * PAGE_SIZE);
518
75b974a8 519 obj = huge_gem_object(vm->i915, DW_PER_PAGE * PAGE_SIZE, size);
791ff39a
CW
520 if (IS_ERR(obj))
521 return obj;
522
f9eb63b9 523 err = file_add_object(file, obj);
791ff39a
CW
524 i915_gem_object_put(obj);
525 if (err)
526 return ERR_PTR(err);
527
250f8c81 528 err = cpu_fill(obj, STACK_MAGIC);
791ff39a
CW
529 if (err) {
530 pr_err("Failed to fill object with cpu, err=%d\n",
531 err);
532 return ERR_PTR(err);
533 }
534
535 list_add_tail(&obj->st_link, objects);
536 return obj;
537}
538
539static unsigned long max_dwords(struct drm_i915_gem_object *obj)
540{
541 unsigned long npages = fake_page_count(obj);
542
543 GEM_BUG_ON(!IS_ALIGNED(npages, DW_PER_PAGE));
544 return npages / DW_PER_PAGE;
545}
546
f2085c8e
CW
547static void throttle_release(struct i915_request **q, int count)
548{
549 int i;
550
551 for (i = 0; i < count; i++) {
552 if (IS_ERR_OR_NULL(q[i]))
553 continue;
554
555 i915_request_put(fetch_and_zero(&q[i]));
556 }
557}
558
559static int throttle(struct intel_context *ce,
560 struct i915_request **q, int count)
561{
562 int i;
563
564 if (!IS_ERR_OR_NULL(q[0])) {
565 if (i915_request_wait(q[0],
566 I915_WAIT_INTERRUPTIBLE,
567 MAX_SCHEDULE_TIMEOUT) < 0)
568 return -EINTR;
569
570 i915_request_put(q[0]);
571 }
572
573 for (i = 0; i < count - 1; i++)
574 q[i] = q[i + 1];
575
576 q[i] = intel_context_create_request(ce);
577 if (IS_ERR(q[i]))
578 return PTR_ERR(q[i]);
579
580 i915_request_get(q[i]);
581 i915_request_add(q[i]);
582
583 return 0;
584}
585
791ff39a
CW
586static int igt_ctx_exec(void *arg)
587{
588 struct drm_i915_private *i915 = arg;
e0695db7
CW
589 struct intel_engine_cs *engine;
590 enum intel_engine_id id;
6e128141 591 int err = -ENODEV;
791ff39a 592
0fdbe58c
CW
593 /*
594 * Create a few different contexts (with different mm) and write
791ff39a
CW
595 * through each ctx/mm using the GPU making sure those writes end
596 * up in the expected pages of our obj.
597 */
598
0fdbe58c
CW
599 if (!DRIVER_CAPS(i915)->has_logical_contexts)
600 return 0;
601
e0695db7
CW
602 for_each_engine(engine, i915, id) {
603 struct drm_i915_gem_object *obj = NULL;
604 unsigned long ncontexts, ndwords, dw;
f2085c8e 605 struct i915_request *tq[5] = {};
e0695db7
CW
606 struct igt_live_test t;
607 struct drm_file *file;
608 IGT_TIMEOUT(end_time);
609 LIST_HEAD(objects);
610
611 if (!intel_engine_can_store_dword(engine))
612 continue;
613
614 if (!engine->context_size)
615 continue; /* No logical context support in HW */
616
617 file = mock_file(i915);
618 if (IS_ERR(file))
619 return PTR_ERR(file);
620
e0695db7
CW
621 err = igt_live_test_begin(&t, i915, __func__, engine->name);
622 if (err)
a4e7ccda 623 goto out_file;
e0695db7
CW
624
625 ncontexts = 0;
626 ndwords = 0;
627 dw = 0;
628 while (!time_after(jiffies, end_time)) {
629 struct i915_gem_context *ctx;
75b974a8 630 struct intel_context *ce;
e0695db7 631
c4e64881 632 ctx = kernel_context(i915);
e0695db7
CW
633 if (IS_ERR(ctx)) {
634 err = PTR_ERR(ctx);
a4e7ccda 635 goto out_file;
e0695db7
CW
636 }
637
75b974a8 638 ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
21b0c32b 639 GEM_BUG_ON(IS_ERR(ce));
75b974a8 640
e0695db7 641 if (!obj) {
75b974a8 642 obj = create_test_object(ce->vm, file, &objects);
e0695db7
CW
643 if (IS_ERR(obj)) {
644 err = PTR_ERR(obj);
75b974a8 645 intel_context_put(ce);
c4e64881 646 kernel_context_close(ctx);
a4e7ccda 647 goto out_file;
e0695db7
CW
648 }
649 }
650
75b974a8 651 err = gpu_fill(ce, obj, dw);
e0695db7 652 if (err) {
2935ed53 653 pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
e0695db7 654 ndwords, dw, max_dwords(obj),
2935ed53 655 engine->name,
a4e7ccda
CW
656 yesno(!!rcu_access_pointer(ctx->vm)),
657 err);
f2085c8e 658 intel_context_put(ce);
c4e64881 659 kernel_context_close(ctx);
a4e7ccda 660 goto out_file;
f2085c8e
CW
661 }
662
663 err = throttle(ce, tq, ARRAY_SIZE(tq));
664 if (err) {
665 intel_context_put(ce);
c4e64881 666 kernel_context_close(ctx);
a4e7ccda 667 goto out_file;
e0695db7
CW
668 }
669
670 if (++dw == max_dwords(obj)) {
671 obj = NULL;
672 dw = 0;
673 }
674
675 ndwords++;
676 ncontexts++;
f2085c8e
CW
677
678 intel_context_put(ce);
c4e64881 679 kernel_context_close(ctx);
e0695db7
CW
680 }
681
682 pr_info("Submitted %lu contexts to %s, filling %lu dwords\n",
683 ncontexts, engine->name, ndwords);
684
685 ncontexts = dw = 0;
686 list_for_each_entry(obj, &objects, st_link) {
687 unsigned int rem =
688 min_t(unsigned int, ndwords - dw, max_dwords(obj));
689
690 err = cpu_check(obj, ncontexts++, rem);
691 if (err)
692 break;
693
694 dw += rem;
695 }
696
a4e7ccda 697out_file:
f2085c8e 698 throttle_release(tq, ARRAY_SIZE(tq));
e0695db7
CW
699 if (igt_live_test_end(&t))
700 err = -EIO;
e0695db7
CW
701
702 mock_file_free(i915, file);
703 if (err)
704 return err;
6582f4f6
CW
705
706 i915_gem_drain_freed_objects(i915);
e0695db7
CW
707 }
708
709 return 0;
710}
711
712static int igt_shared_ctx_exec(void *arg)
713{
714 struct drm_i915_private *i915 = arg;
f2085c8e 715 struct i915_request *tq[5] = {};
e0695db7
CW
716 struct i915_gem_context *parent;
717 struct intel_engine_cs *engine;
718 enum intel_engine_id id;
719 struct igt_live_test t;
720 struct drm_file *file;
721 int err = 0;
722
723 /*
724 * Create a few different contexts with the same mm and write
725 * through each ctx using the GPU making sure those writes end
726 * up in the expected pages of our obj.
727 */
728 if (!DRIVER_CAPS(i915)->has_logical_contexts)
729 return 0;
730
ef47a0e0
CW
731 file = mock_file(i915);
732 if (IS_ERR(file))
733 return PTR_ERR(file);
734
e0695db7
CW
735 parent = live_context(i915, file);
736 if (IS_ERR(parent)) {
737 err = PTR_ERR(parent);
a4e7ccda 738 goto out_file;
e0695db7
CW
739 }
740
e568ac38 741 if (!parent->vm) { /* not full-ppgtt; nothing to share */
e0695db7 742 err = 0;
a4e7ccda 743 goto out_file;
e0695db7
CW
744 }
745
e4a8c813 746 err = igt_live_test_begin(&t, i915, __func__, "");
8dd0f8d3 747 if (err)
a4e7ccda 748 goto out_file;
8dd0f8d3 749
e0695db7
CW
750 for_each_engine(engine, i915, id) {
751 unsigned long ncontexts, ndwords, dw;
752 struct drm_i915_gem_object *obj = NULL;
753 IGT_TIMEOUT(end_time);
754 LIST_HEAD(objects);
791ff39a 755
e0695db7
CW
756 if (!intel_engine_can_store_dword(engine))
757 continue;
791ff39a 758
e0695db7
CW
759 dw = 0;
760 ndwords = 0;
761 ncontexts = 0;
762 while (!time_after(jiffies, end_time)) {
763 struct i915_gem_context *ctx;
75b974a8 764 struct intel_context *ce;
c9d08cc3 765
e0695db7
CW
766 ctx = kernel_context(i915);
767 if (IS_ERR(ctx)) {
768 err = PTR_ERR(ctx);
769 goto out_test;
770 }
0fdbe58c 771
a4e7ccda 772 mutex_lock(&ctx->mutex);
e568ac38 773 __assign_ppgtt(ctx, parent->vm);
a4e7ccda 774 mutex_unlock(&ctx->mutex);
f2f5c061 775
75b974a8 776 ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
21b0c32b
CW
777 GEM_BUG_ON(IS_ERR(ce));
778
ca83d584 779 if (!obj) {
75b974a8 780 obj = create_test_object(parent->vm, file, &objects);
791ff39a
CW
781 if (IS_ERR(obj)) {
782 err = PTR_ERR(obj);
75b974a8 783 intel_context_put(ce);
e0695db7
CW
784 kernel_context_close(ctx);
785 goto out_test;
791ff39a
CW
786 }
787 }
788
75b974a8 789 err = gpu_fill(ce, obj, dw);
791ff39a 790 if (err) {
2935ed53 791 pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
791ff39a 792 ndwords, dw, max_dwords(obj),
2935ed53 793 engine->name,
a4e7ccda
CW
794 yesno(!!rcu_access_pointer(ctx->vm)),
795 err);
f2085c8e
CW
796 intel_context_put(ce);
797 kernel_context_close(ctx);
798 goto out_test;
799 }
800
801 err = throttle(ce, tq, ARRAY_SIZE(tq));
802 if (err) {
803 intel_context_put(ce);
804 kernel_context_close(ctx);
e0695db7 805 goto out_test;
791ff39a
CW
806 }
807
ca83d584
CW
808 if (++dw == max_dwords(obj)) {
809 obj = NULL;
791ff39a 810 dw = 0;
ca83d584 811 }
e0695db7 812
791ff39a 813 ndwords++;
e0695db7 814 ncontexts++;
f2085c8e
CW
815
816 intel_context_put(ce);
817 kernel_context_close(ctx);
791ff39a 818 }
e0695db7
CW
819 pr_info("Submitted %lu contexts to %s, filling %lu dwords\n",
820 ncontexts, engine->name, ndwords);
791ff39a 821
e0695db7
CW
822 ncontexts = dw = 0;
823 list_for_each_entry(obj, &objects, st_link) {
824 unsigned int rem =
825 min_t(unsigned int, ndwords - dw, max_dwords(obj));
791ff39a 826
e0695db7
CW
827 err = cpu_check(obj, ncontexts++, rem);
828 if (err)
829 goto out_test;
791ff39a 830
e0695db7
CW
831 dw += rem;
832 }
6582f4f6 833
6582f4f6 834 i915_gem_drain_freed_objects(i915);
791ff39a 835 }
e0695db7 836out_test:
f2085c8e 837 throttle_release(tq, ARRAY_SIZE(tq));
e4a8c813 838 if (igt_live_test_end(&t))
7c2f5bc5 839 err = -EIO;
a4e7ccda 840out_file:
791ff39a
CW
841 mock_file_free(i915, file);
842 return err;
843}
844
c06ee6ff
TU
845static struct i915_vma *rpcs_query_batch(struct i915_vma *vma)
846{
847 struct drm_i915_gem_object *obj;
848 u32 *cmd;
849 int err;
850
851 if (INTEL_GEN(vma->vm->i915) < 8)
852 return ERR_PTR(-EINVAL);
853
854 obj = i915_gem_object_create_internal(vma->vm->i915, PAGE_SIZE);
855 if (IS_ERR(obj))
856 return ERR_CAST(obj);
857
858 cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
859 if (IS_ERR(cmd)) {
860 err = PTR_ERR(cmd);
861 goto err;
862 }
863
864 *cmd++ = MI_STORE_REGISTER_MEM_GEN8;
865 *cmd++ = i915_mmio_reg_offset(GEN8_R_PWR_CLK_STATE);
866 *cmd++ = lower_32_bits(vma->node.start);
867 *cmd++ = upper_32_bits(vma->node.start);
868 *cmd = MI_BATCH_BUFFER_END;
869
a679f58d 870 __i915_gem_object_flush_map(obj, 0, 64);
c06ee6ff
TU
871 i915_gem_object_unpin_map(obj);
872
75b974a8
CW
873 intel_gt_chipset_flush(vma->vm->gt);
874
c06ee6ff
TU
875 vma = i915_vma_instance(obj, vma->vm, NULL);
876 if (IS_ERR(vma)) {
877 err = PTR_ERR(vma);
878 goto err;
879 }
880
881 err = i915_vma_pin(vma, 0, 0, PIN_USER);
882 if (err)
883 goto err;
884
885 return vma;
886
887err:
888 i915_gem_object_put(obj);
889 return ERR_PTR(err);
890}
891
892static int
893emit_rpcs_query(struct drm_i915_gem_object *obj,
1b1ae407 894 struct intel_context *ce,
c06ee6ff
TU
895 struct i915_request **rq_out)
896{
897 struct i915_request *rq;
898 struct i915_vma *batch;
899 struct i915_vma *vma;
900 int err;
901
1b1ae407 902 GEM_BUG_ON(!intel_engine_can_store_dword(ce->engine));
c06ee6ff 903
f5d974f9 904 vma = i915_vma_instance(obj, ce->vm, NULL);
c06ee6ff
TU
905 if (IS_ERR(vma))
906 return PTR_ERR(vma);
907
6951e589 908 i915_gem_object_lock(obj);
c06ee6ff 909 err = i915_gem_object_set_to_gtt_domain(obj, false);
6951e589 910 i915_gem_object_unlock(obj);
c06ee6ff
TU
911 if (err)
912 return err;
913
914 err = i915_vma_pin(vma, 0, 0, PIN_USER);
915 if (err)
916 return err;
917
918 batch = rpcs_query_batch(vma);
919 if (IS_ERR(batch)) {
920 err = PTR_ERR(batch);
921 goto err_vma;
922 }
923
1b1ae407 924 rq = i915_request_create(ce);
c06ee6ff
TU
925 if (IS_ERR(rq)) {
926 err = PTR_ERR(rq);
927 goto err_batch;
928 }
929
1b1ae407
CW
930 err = rq->engine->emit_bb_start(rq,
931 batch->node.start, batch->node.size,
932 0);
c06ee6ff
TU
933 if (err)
934 goto err_request;
935
6951e589 936 i915_vma_lock(batch);
70d6894d
CW
937 err = i915_request_await_object(rq, batch->obj, false);
938 if (err == 0)
939 err = i915_vma_move_to_active(batch, rq, 0);
6951e589 940 i915_vma_unlock(batch);
c06ee6ff
TU
941 if (err)
942 goto skip_request;
943
6951e589 944 i915_vma_lock(vma);
70d6894d
CW
945 err = i915_request_await_object(rq, vma->obj, true);
946 if (err == 0)
947 err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
6951e589 948 i915_vma_unlock(vma);
c06ee6ff
TU
949 if (err)
950 goto skip_request;
951
2850748e 952 i915_vma_unpin_and_release(&batch, 0);
c06ee6ff
TU
953 i915_vma_unpin(vma);
954
955 *rq_out = i915_request_get(rq);
956
957 i915_request_add(rq);
958
959 return 0;
960
961skip_request:
962 i915_request_skip(rq, err);
963err_request:
964 i915_request_add(rq);
965err_batch:
2850748e 966 i915_vma_unpin_and_release(&batch, 0);
c06ee6ff
TU
967err_vma:
968 i915_vma_unpin(vma);
969
970 return err;
971}
972
973#define TEST_IDLE BIT(0)
974#define TEST_BUSY BIT(1)
975#define TEST_RESET BIT(2)
976
977static int
f277bc0c 978__sseu_prepare(const char *name,
c06ee6ff 979 unsigned int flags,
1b1ae407 980 struct intel_context *ce,
2a4a2754 981 struct igt_spinner **spin)
c06ee6ff 982{
2a4a2754
CW
983 struct i915_request *rq;
984 int ret;
c06ee6ff 985
2a4a2754
CW
986 *spin = NULL;
987 if (!(flags & (TEST_BUSY | TEST_RESET)))
988 return 0;
c06ee6ff 989
2a4a2754
CW
990 *spin = kzalloc(sizeof(**spin), GFP_KERNEL);
991 if (!*spin)
992 return -ENOMEM;
c06ee6ff 993
f277bc0c 994 ret = igt_spinner_init(*spin, ce->engine->gt);
2a4a2754
CW
995 if (ret)
996 goto err_free;
c06ee6ff 997
f277bc0c 998 rq = igt_spinner_create_request(*spin, ce, MI_NOOP);
2a4a2754
CW
999 if (IS_ERR(rq)) {
1000 ret = PTR_ERR(rq);
1001 goto err_fini;
1002 }
c06ee6ff 1003
2a4a2754 1004 i915_request_add(rq);
c06ee6ff 1005
2a4a2754
CW
1006 if (!igt_wait_for_spinner(*spin, rq)) {
1007 pr_err("%s: Spinner failed to start!\n", name);
1008 ret = -ETIMEDOUT;
1009 goto err_end;
c06ee6ff
TU
1010 }
1011
2a4a2754
CW
1012 return 0;
1013
1014err_end:
1015 igt_spinner_end(*spin);
1016err_fini:
1017 igt_spinner_fini(*spin);
1018err_free:
1019 kfree(fetch_and_zero(spin));
c06ee6ff
TU
1020 return ret;
1021}
1022
1023static int
f277bc0c 1024__read_slice_count(struct intel_context *ce,
c06ee6ff
TU
1025 struct drm_i915_gem_object *obj,
1026 struct igt_spinner *spin,
1027 u32 *rpcs)
1028{
1029 struct i915_request *rq = NULL;
1030 u32 s_mask, s_shift;
1031 unsigned int cnt;
1032 u32 *buf, val;
1033 long ret;
1034
1b1ae407 1035 ret = emit_rpcs_query(obj, ce, &rq);
c06ee6ff
TU
1036 if (ret)
1037 return ret;
1038
1039 if (spin)
1040 igt_spinner_end(spin);
1041
2f530945 1042 ret = i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT);
c06ee6ff
TU
1043 i915_request_put(rq);
1044 if (ret < 0)
1045 return ret;
1046
1047 buf = i915_gem_object_pin_map(obj, I915_MAP_WB);
1048 if (IS_ERR(buf)) {
1049 ret = PTR_ERR(buf);
1050 return ret;
1051 }
1052
f277bc0c 1053 if (INTEL_GEN(ce->engine->i915) >= 11) {
c06ee6ff
TU
1054 s_mask = GEN11_RPCS_S_CNT_MASK;
1055 s_shift = GEN11_RPCS_S_CNT_SHIFT;
1056 } else {
1057 s_mask = GEN8_RPCS_S_CNT_MASK;
1058 s_shift = GEN8_RPCS_S_CNT_SHIFT;
1059 }
1060
1061 val = *buf;
1062 cnt = (val & s_mask) >> s_shift;
1063 *rpcs = val;
1064
1065 i915_gem_object_unpin_map(obj);
1066
1067 return cnt;
1068}
1069
1070static int
1071__check_rpcs(const char *name, u32 rpcs, int slices, unsigned int expected,
1072 const char *prefix, const char *suffix)
1073{
1074 if (slices == expected)
1075 return 0;
1076
1077 if (slices < 0) {
1078 pr_err("%s: %s read slice count failed with %d%s\n",
1079 name, prefix, slices, suffix);
1080 return slices;
1081 }
1082
1083 pr_err("%s: %s slice count %d is not %u%s\n",
1084 name, prefix, slices, expected, suffix);
1085
1086 pr_info("RPCS=0x%x; %u%sx%u%s\n",
1087 rpcs, slices,
1088 (rpcs & GEN8_RPCS_S_CNT_ENABLE) ? "*" : "",
1089 (rpcs & GEN8_RPCS_SS_CNT_MASK) >> GEN8_RPCS_SS_CNT_SHIFT,
1090 (rpcs & GEN8_RPCS_SS_CNT_ENABLE) ? "*" : "");
1091
1092 return -EINVAL;
1093}
1094
1095static int
f277bc0c 1096__sseu_finish(const char *name,
c06ee6ff 1097 unsigned int flags,
1b1ae407 1098 struct intel_context *ce,
c06ee6ff
TU
1099 struct drm_i915_gem_object *obj,
1100 unsigned int expected,
1101 struct igt_spinner *spin)
1102{
1b1ae407 1103 unsigned int slices = hweight32(ce->engine->sseu.slice_mask);
c06ee6ff
TU
1104 u32 rpcs = 0;
1105 int ret = 0;
1106
1107 if (flags & TEST_RESET) {
cb823ed9 1108 ret = intel_engine_reset(ce->engine, "sseu");
c06ee6ff
TU
1109 if (ret)
1110 goto out;
1111 }
1112
f277bc0c 1113 ret = __read_slice_count(ce, obj,
c06ee6ff
TU
1114 flags & TEST_RESET ? NULL : spin, &rpcs);
1115 ret = __check_rpcs(name, rpcs, ret, expected, "Context", "!");
1116 if (ret)
1117 goto out;
1118
f277bc0c 1119 ret = __read_slice_count(ce->engine->kernel_context, obj, NULL, &rpcs);
c06ee6ff
TU
1120 ret = __check_rpcs(name, rpcs, ret, slices, "Kernel context", "!");
1121
1122out:
1123 if (spin)
1124 igt_spinner_end(spin);
1125
1126 if ((flags & TEST_IDLE) && ret == 0) {
66101975 1127 ret = intel_gt_wait_for_idle(ce->engine->gt,
f33a8a51 1128 MAX_SCHEDULE_TIMEOUT);
c06ee6ff
TU
1129 if (ret)
1130 return ret;
1131
f277bc0c 1132 ret = __read_slice_count(ce, obj, NULL, &rpcs);
c06ee6ff
TU
1133 ret = __check_rpcs(name, rpcs, ret, expected,
1134 "Context", " after idle!");
1135 }
1136
1137 return ret;
1138}
1139
1140static int
f277bc0c 1141__sseu_test(const char *name,
c06ee6ff 1142 unsigned int flags,
1b1ae407 1143 struct intel_context *ce,
c06ee6ff
TU
1144 struct drm_i915_gem_object *obj,
1145 struct intel_sseu sseu)
1146{
1147 struct igt_spinner *spin = NULL;
c06ee6ff
TU
1148 int ret;
1149
f277bc0c 1150 ret = __sseu_prepare(name, flags, ce, &spin);
c06ee6ff 1151 if (ret)
f7f28de7 1152 return ret;
c06ee6ff 1153
7e805762 1154 ret = intel_context_reconfigure_sseu(ce, sseu);
c06ee6ff 1155 if (ret)
2a4a2754 1156 goto out_spin;
c06ee6ff 1157
f277bc0c 1158 ret = __sseu_finish(name, flags, ce, obj,
c06ee6ff
TU
1159 hweight32(sseu.slice_mask), spin);
1160
2a4a2754 1161out_spin:
c06ee6ff
TU
1162 if (spin) {
1163 igt_spinner_end(spin);
1164 igt_spinner_fini(spin);
1165 kfree(spin);
1166 }
c06ee6ff
TU
1167 return ret;
1168}
1169
1170static int
1171__igt_ctx_sseu(struct drm_i915_private *i915,
1172 const char *name,
1173 unsigned int flags)
1174{
8a68d464 1175 struct intel_engine_cs *engine = i915->engine[RCS0];
c06ee6ff
TU
1176 struct drm_i915_gem_object *obj;
1177 struct i915_gem_context *ctx;
1b1ae407 1178 struct intel_context *ce;
c06ee6ff 1179 struct intel_sseu pg_sseu;
c06ee6ff
TU
1180 struct drm_file *file;
1181 int ret;
1182
8f856c74 1183 if (INTEL_GEN(i915) < 9 || !engine)
c06ee6ff
TU
1184 return 0;
1185
1186 if (!RUNTIME_INFO(i915)->sseu.has_slice_pg)
1187 return 0;
1188
8f856c74 1189 if (hweight32(engine->sseu.slice_mask) < 2)
c06ee6ff
TU
1190 return 0;
1191
1192 /*
1193 * Gen11 VME friendly power-gated configuration with half enabled
1194 * sub-slices.
1195 */
8f856c74 1196 pg_sseu = engine->sseu;
c06ee6ff
TU
1197 pg_sseu.slice_mask = 1;
1198 pg_sseu.subslice_mask =
8f856c74 1199 ~(~0 << (hweight32(engine->sseu.subslice_mask) / 2));
c06ee6ff
TU
1200
1201 pr_info("SSEU subtest '%s', flags=%x, def_slices=%u, pg_slices=%u\n",
8f856c74 1202 name, flags, hweight32(engine->sseu.slice_mask),
c06ee6ff
TU
1203 hweight32(pg_sseu.slice_mask));
1204
1205 file = mock_file(i915);
1206 if (IS_ERR(file))
1207 return PTR_ERR(file);
1208
1209 if (flags & TEST_RESET)
cb823ed9 1210 igt_global_reset_lock(&i915->gt);
c06ee6ff 1211
3aa9945a 1212 ctx = live_context(i915, file);
c06ee6ff
TU
1213 if (IS_ERR(ctx)) {
1214 ret = PTR_ERR(ctx);
1215 goto out_unlock;
1216 }
e4106dae 1217 i915_gem_context_clear_bannable(ctx); /* to reset and beyond! */
c06ee6ff
TU
1218
1219 obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
1220 if (IS_ERR(obj)) {
1221 ret = PTR_ERR(obj);
1222 goto out_unlock;
1223 }
1224
5e2a0419 1225 ce = i915_gem_context_get_engine(ctx, RCS0);
1b1ae407
CW
1226 if (IS_ERR(ce)) {
1227 ret = PTR_ERR(ce);
60a0933b 1228 goto out_put;
1b1ae407
CW
1229 }
1230
1231 ret = intel_context_pin(ce);
1232 if (ret)
1233 goto out_context;
1234
c06ee6ff 1235 /* First set the default mask. */
f277bc0c 1236 ret = __sseu_test(name, flags, ce, obj, engine->sseu);
c06ee6ff
TU
1237 if (ret)
1238 goto out_fail;
1239
1240 /* Then set a power-gated configuration. */
f277bc0c 1241 ret = __sseu_test(name, flags, ce, obj, pg_sseu);
c06ee6ff
TU
1242 if (ret)
1243 goto out_fail;
1244
1245 /* Back to defaults. */
f277bc0c 1246 ret = __sseu_test(name, flags, ce, obj, engine->sseu);
c06ee6ff
TU
1247 if (ret)
1248 goto out_fail;
1249
1250 /* One last power-gated configuration for the road. */
f277bc0c 1251 ret = __sseu_test(name, flags, ce, obj, pg_sseu);
c06ee6ff
TU
1252 if (ret)
1253 goto out_fail;
1254
1255out_fail:
7e805762 1256 if (igt_flush_test(i915))
c06ee6ff
TU
1257 ret = -EIO;
1258
1b1ae407
CW
1259 intel_context_unpin(ce);
1260out_context:
1261 intel_context_put(ce);
60a0933b 1262out_put:
1b1ae407 1263 i915_gem_object_put(obj);
c06ee6ff
TU
1264
1265out_unlock:
c06ee6ff 1266 if (flags & TEST_RESET)
cb823ed9 1267 igt_global_reset_unlock(&i915->gt);
c06ee6ff
TU
1268
1269 mock_file_free(i915, file);
1270
1271 if (ret)
1272 pr_err("%s: Failed with %d!\n", name, ret);
1273
1274 return ret;
1275}
1276
1277static int igt_ctx_sseu(void *arg)
1278{
1279 struct {
1280 const char *name;
1281 unsigned int flags;
1282 } *phase, phases[] = {
1283 { .name = "basic", .flags = 0 },
1284 { .name = "idle", .flags = TEST_IDLE },
1285 { .name = "busy", .flags = TEST_BUSY },
1286 { .name = "busy-reset", .flags = TEST_BUSY | TEST_RESET },
1287 { .name = "busy-idle", .flags = TEST_BUSY | TEST_IDLE },
1288 { .name = "reset-idle", .flags = TEST_RESET | TEST_IDLE },
1289 };
1290 unsigned int i;
1291 int ret = 0;
1292
1293 for (i = 0, phase = phases; ret == 0 && i < ARRAY_SIZE(phases);
1294 i++, phase++)
1295 ret = __igt_ctx_sseu(arg, phase->name, phase->flags);
1296
1297 return ret;
1298}
1299
250f8c81
JB
1300static int igt_ctx_readonly(void *arg)
1301{
1302 struct drm_i915_private *i915 = arg;
1303 struct drm_i915_gem_object *obj = NULL;
f2085c8e 1304 struct i915_request *tq[5] = {};
e568ac38 1305 struct i915_address_space *vm;
8dd0f8d3 1306 struct i915_gem_context *ctx;
e0695db7 1307 unsigned long idx, ndwords, dw;
e4a8c813 1308 struct igt_live_test t;
250f8c81
JB
1309 struct drm_file *file;
1310 I915_RND_STATE(prng);
1311 IGT_TIMEOUT(end_time);
1312 LIST_HEAD(objects);
250f8c81
JB
1313 int err = -ENODEV;
1314
1315 /*
1316 * Create a few read-only objects (with the occasional writable object)
1317 * and try to write into these object checking that the GPU discards
1318 * any write to a read-only object.
1319 */
1320
1321 file = mock_file(i915);
1322 if (IS_ERR(file))
1323 return PTR_ERR(file);
1324
e4a8c813 1325 err = igt_live_test_begin(&t, i915, __func__, "");
8dd0f8d3 1326 if (err)
a4e7ccda 1327 goto out_file;
8dd0f8d3 1328
3aa9945a 1329 ctx = live_context(i915, file);
250f8c81
JB
1330 if (IS_ERR(ctx)) {
1331 err = PTR_ERR(ctx);
a4e7ccda 1332 goto out_file;
250f8c81
JB
1333 }
1334
a4e7ccda
CW
1335 rcu_read_lock();
1336 vm = rcu_dereference(ctx->vm) ?: &i915->ggtt.alias->vm;
e568ac38 1337 if (!vm || !vm->has_read_only) {
a4e7ccda 1338 rcu_read_unlock();
250f8c81 1339 err = 0;
a4e7ccda 1340 goto out_file;
250f8c81 1341 }
a4e7ccda 1342 rcu_read_unlock();
250f8c81
JB
1343
1344 ndwords = 0;
1345 dw = 0;
1346 while (!time_after(jiffies, end_time)) {
75b974a8
CW
1347 struct i915_gem_engines_iter it;
1348 struct intel_context *ce;
250f8c81 1349
75b974a8
CW
1350 for_each_gem_engine(ce,
1351 i915_gem_context_lock_engines(ctx), it) {
1352 if (!intel_engine_can_store_dword(ce->engine))
250f8c81
JB
1353 continue;
1354
1355 if (!obj) {
75b974a8 1356 obj = create_test_object(ce->vm, file, &objects);
250f8c81
JB
1357 if (IS_ERR(obj)) {
1358 err = PTR_ERR(obj);
75b974a8 1359 i915_gem_context_unlock_engines(ctx);
a4e7ccda 1360 goto out_file;
250f8c81
JB
1361 }
1362
3e977ac6
CW
1363 if (prandom_u32_state(&prng) & 1)
1364 i915_gem_object_set_readonly(obj);
250f8c81
JB
1365 }
1366
75b974a8 1367 err = gpu_fill(ce, obj, dw);
250f8c81 1368 if (err) {
2935ed53 1369 pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
250f8c81 1370 ndwords, dw, max_dwords(obj),
a4e7ccda
CW
1371 ce->engine->name,
1372 yesno(!!rcu_access_pointer(ctx->vm)),
1373 err);
75b974a8 1374 i915_gem_context_unlock_engines(ctx);
a4e7ccda 1375 goto out_file;
250f8c81
JB
1376 }
1377
f2085c8e
CW
1378 err = throttle(ce, tq, ARRAY_SIZE(tq));
1379 if (err) {
1380 i915_gem_context_unlock_engines(ctx);
a4e7ccda 1381 goto out_file;
f2085c8e
CW
1382 }
1383
250f8c81
JB
1384 if (++dw == max_dwords(obj)) {
1385 obj = NULL;
1386 dw = 0;
1387 }
1388 ndwords++;
1389 }
75b974a8 1390 i915_gem_context_unlock_engines(ctx);
250f8c81
JB
1391 }
1392 pr_info("Submitted %lu dwords (across %u engines)\n",
8a68d464 1393 ndwords, RUNTIME_INFO(i915)->num_engines);
250f8c81
JB
1394
1395 dw = 0;
e0695db7 1396 idx = 0;
250f8c81
JB
1397 list_for_each_entry(obj, &objects, st_link) {
1398 unsigned int rem =
1399 min_t(unsigned int, ndwords - dw, max_dwords(obj));
1400 unsigned int num_writes;
1401
1402 num_writes = rem;
3e977ac6 1403 if (i915_gem_object_is_readonly(obj))
250f8c81
JB
1404 num_writes = 0;
1405
e0695db7 1406 err = cpu_check(obj, idx++, num_writes);
250f8c81
JB
1407 if (err)
1408 break;
1409
1410 dw += rem;
1411 }
1412
a4e7ccda 1413out_file:
f2085c8e 1414 throttle_release(tq, ARRAY_SIZE(tq));
e4a8c813 1415 if (igt_live_test_end(&t))
250f8c81 1416 err = -EIO;
250f8c81
JB
1417
1418 mock_file_free(i915, file);
1419 return err;
1420}
1421
a4e7ccda 1422static int check_scratch(struct i915_address_space *vm, u64 offset)
c5def85c
CW
1423{
1424 struct drm_mm_node *node =
a4e7ccda 1425 __drm_mm_interval_first(&vm->mm,
c5def85c
CW
1426 offset, offset + sizeof(u32) - 1);
1427 if (!node || node->start > offset)
1428 return 0;
1429
1430 GEM_BUG_ON(offset >= node->start + node->size);
1431
1432 pr_err("Target offset 0x%08x_%08x overlaps with a node in the mm!\n",
1433 upper_32_bits(offset), lower_32_bits(offset));
1434 return -EINVAL;
1435}
1436
1437static int write_to_scratch(struct i915_gem_context *ctx,
1438 struct intel_engine_cs *engine,
1439 u64 offset, u32 value)
1440{
1441 struct drm_i915_private *i915 = ctx->i915;
1442 struct drm_i915_gem_object *obj;
a4e7ccda 1443 struct i915_address_space *vm;
c5def85c
CW
1444 struct i915_request *rq;
1445 struct i915_vma *vma;
1446 u32 *cmd;
1447 int err;
1448
1449 GEM_BUG_ON(offset < I915_GTT_PAGE_SIZE);
1450
1451 obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
1452 if (IS_ERR(obj))
1453 return PTR_ERR(obj);
1454
1455 cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
1456 if (IS_ERR(cmd)) {
1457 err = PTR_ERR(cmd);
1458 goto err;
1459 }
1460
1461 *cmd++ = MI_STORE_DWORD_IMM_GEN4;
1462 if (INTEL_GEN(i915) >= 8) {
1463 *cmd++ = lower_32_bits(offset);
1464 *cmd++ = upper_32_bits(offset);
1465 } else {
1466 *cmd++ = 0;
1467 *cmd++ = offset;
1468 }
1469 *cmd++ = value;
1470 *cmd = MI_BATCH_BUFFER_END;
a679f58d 1471 __i915_gem_object_flush_map(obj, 0, 64);
c5def85c
CW
1472 i915_gem_object_unpin_map(obj);
1473
75b974a8
CW
1474 intel_gt_chipset_flush(engine->gt);
1475
a4e7ccda
CW
1476 vm = i915_gem_context_get_vm_rcu(ctx);
1477 vma = i915_vma_instance(obj, vm, NULL);
c5def85c
CW
1478 if (IS_ERR(vma)) {
1479 err = PTR_ERR(vma);
a4e7ccda 1480 goto err_vm;
c5def85c
CW
1481 }
1482
1483 err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_OFFSET_FIXED);
1484 if (err)
a4e7ccda 1485 goto err_vm;
c5def85c 1486
a4e7ccda 1487 err = check_scratch(vm, offset);
c5def85c
CW
1488 if (err)
1489 goto err_unpin;
1490
46472b3e 1491 rq = igt_request_alloc(ctx, engine);
c5def85c
CW
1492 if (IS_ERR(rq)) {
1493 err = PTR_ERR(rq);
1494 goto err_unpin;
1495 }
1496
1497 err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, 0);
1498 if (err)
1499 goto err_request;
1500
6951e589 1501 i915_vma_lock(vma);
70d6894d
CW
1502 err = i915_request_await_object(rq, vma->obj, false);
1503 if (err == 0)
1504 err = i915_vma_move_to_active(vma, rq, 0);
6951e589 1505 i915_vma_unlock(vma);
c5def85c
CW
1506 if (err)
1507 goto skip_request;
1508
2850748e 1509 i915_vma_unpin_and_release(&vma, 0);
c5def85c
CW
1510
1511 i915_request_add(rq);
1512
a4e7ccda 1513 i915_vm_put(vm);
c5def85c
CW
1514 return 0;
1515
1516skip_request:
1517 i915_request_skip(rq, err);
1518err_request:
1519 i915_request_add(rq);
1520err_unpin:
1521 i915_vma_unpin(vma);
a4e7ccda
CW
1522err_vm:
1523 i915_vm_put(vm);
c5def85c
CW
1524err:
1525 i915_gem_object_put(obj);
1526 return err;
1527}
1528
1529static int read_from_scratch(struct i915_gem_context *ctx,
1530 struct intel_engine_cs *engine,
1531 u64 offset, u32 *value)
1532{
1533 struct drm_i915_private *i915 = ctx->i915;
1534 struct drm_i915_gem_object *obj;
a4e7ccda 1535 struct i915_address_space *vm;
c5def85c
CW
1536 const u32 RCS_GPR0 = 0x2600; /* not all engines have their own GPR! */
1537 const u32 result = 0x100;
1538 struct i915_request *rq;
1539 struct i915_vma *vma;
1540 u32 *cmd;
1541 int err;
1542
1543 GEM_BUG_ON(offset < I915_GTT_PAGE_SIZE);
1544
1545 obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
1546 if (IS_ERR(obj))
1547 return PTR_ERR(obj);
1548
1549 cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
1550 if (IS_ERR(cmd)) {
1551 err = PTR_ERR(cmd);
1552 goto err;
1553 }
1554
1555 memset(cmd, POISON_INUSE, PAGE_SIZE);
1556 if (INTEL_GEN(i915) >= 8) {
1557 *cmd++ = MI_LOAD_REGISTER_MEM_GEN8;
1558 *cmd++ = RCS_GPR0;
1559 *cmd++ = lower_32_bits(offset);
1560 *cmd++ = upper_32_bits(offset);
1561 *cmd++ = MI_STORE_REGISTER_MEM_GEN8;
1562 *cmd++ = RCS_GPR0;
1563 *cmd++ = result;
1564 *cmd++ = 0;
1565 } else {
1566 *cmd++ = MI_LOAD_REGISTER_MEM;
1567 *cmd++ = RCS_GPR0;
1568 *cmd++ = offset;
1569 *cmd++ = MI_STORE_REGISTER_MEM;
1570 *cmd++ = RCS_GPR0;
1571 *cmd++ = result;
1572 }
1573 *cmd = MI_BATCH_BUFFER_END;
c5def85c 1574
a679f58d
CW
1575 i915_gem_object_flush_map(obj);
1576 i915_gem_object_unpin_map(obj);
c5def85c 1577
75b974a8
CW
1578 intel_gt_chipset_flush(engine->gt);
1579
a4e7ccda
CW
1580 vm = i915_gem_context_get_vm_rcu(ctx);
1581 vma = i915_vma_instance(obj, vm, NULL);
c5def85c
CW
1582 if (IS_ERR(vma)) {
1583 err = PTR_ERR(vma);
a4e7ccda 1584 goto err_vm;
c5def85c
CW
1585 }
1586
1587 err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_OFFSET_FIXED);
1588 if (err)
a4e7ccda 1589 goto err_vm;
c5def85c 1590
a4e7ccda 1591 err = check_scratch(vm, offset);
c5def85c
CW
1592 if (err)
1593 goto err_unpin;
1594
46472b3e 1595 rq = igt_request_alloc(ctx, engine);
c5def85c
CW
1596 if (IS_ERR(rq)) {
1597 err = PTR_ERR(rq);
1598 goto err_unpin;
1599 }
1600
1601 err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, 0);
1602 if (err)
1603 goto err_request;
1604
6951e589 1605 i915_vma_lock(vma);
70d6894d
CW
1606 err = i915_request_await_object(rq, vma->obj, true);
1607 if (err == 0)
1608 err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
6951e589 1609 i915_vma_unlock(vma);
c5def85c
CW
1610 if (err)
1611 goto skip_request;
1612
1613 i915_vma_unpin(vma);
1614 i915_vma_close(vma);
1615
1616 i915_request_add(rq);
1617
6951e589 1618 i915_gem_object_lock(obj);
c5def85c 1619 err = i915_gem_object_set_to_cpu_domain(obj, false);
6951e589 1620 i915_gem_object_unlock(obj);
c5def85c 1621 if (err)
a4e7ccda 1622 goto err_vm;
c5def85c
CW
1623
1624 cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
1625 if (IS_ERR(cmd)) {
1626 err = PTR_ERR(cmd);
a4e7ccda 1627 goto err_vm;
c5def85c
CW
1628 }
1629
1630 *value = cmd[result / sizeof(*cmd)];
1631 i915_gem_object_unpin_map(obj);
1632 i915_gem_object_put(obj);
1633
1634 return 0;
1635
1636skip_request:
1637 i915_request_skip(rq, err);
1638err_request:
1639 i915_request_add(rq);
1640err_unpin:
1641 i915_vma_unpin(vma);
a4e7ccda
CW
1642err_vm:
1643 i915_vm_put(vm);
c5def85c
CW
1644err:
1645 i915_gem_object_put(obj);
1646 return err;
1647}
1648
1649static int igt_vm_isolation(void *arg)
1650{
1651 struct drm_i915_private *i915 = arg;
1652 struct i915_gem_context *ctx_a, *ctx_b;
1653 struct intel_engine_cs *engine;
e4a8c813 1654 struct igt_live_test t;
c5def85c
CW
1655 struct drm_file *file;
1656 I915_RND_STATE(prng);
1657 unsigned long count;
c5def85c
CW
1658 unsigned int id;
1659 u64 vm_total;
1660 int err;
1661
1662 if (INTEL_GEN(i915) < 7)
1663 return 0;
1664
1665 /*
1666 * The simple goal here is that a write into one context is not
1667 * observed in a second (separate page tables and scratch).
1668 */
1669
1670 file = mock_file(i915);
1671 if (IS_ERR(file))
1672 return PTR_ERR(file);
1673
e4a8c813 1674 err = igt_live_test_begin(&t, i915, __func__, "");
c5def85c 1675 if (err)
a4e7ccda 1676 goto out_file;
c5def85c 1677
3aa9945a 1678 ctx_a = live_context(i915, file);
c5def85c
CW
1679 if (IS_ERR(ctx_a)) {
1680 err = PTR_ERR(ctx_a);
a4e7ccda 1681 goto out_file;
c5def85c
CW
1682 }
1683
3aa9945a 1684 ctx_b = live_context(i915, file);
c5def85c
CW
1685 if (IS_ERR(ctx_b)) {
1686 err = PTR_ERR(ctx_b);
a4e7ccda 1687 goto out_file;
c5def85c
CW
1688 }
1689
1690 /* We can only test vm isolation, if the vm are distinct */
e568ac38 1691 if (ctx_a->vm == ctx_b->vm)
a4e7ccda 1692 goto out_file;
c5def85c 1693
e568ac38
CW
1694 vm_total = ctx_a->vm->total;
1695 GEM_BUG_ON(ctx_b->vm->total != vm_total);
c5def85c
CW
1696 vm_total -= I915_GTT_PAGE_SIZE;
1697
c5def85c
CW
1698 count = 0;
1699 for_each_engine(engine, i915, id) {
1700 IGT_TIMEOUT(end_time);
1701 unsigned long this = 0;
1702
1703 if (!intel_engine_can_store_dword(engine))
1704 continue;
1705
1706 while (!__igt_timeout(end_time, NULL)) {
1707 u32 value = 0xc5c5c5c5;
1708 u64 offset;
1709
1710 div64_u64_rem(i915_prandom_u64_state(&prng),
1711 vm_total, &offset);
bf1315b8 1712 offset = round_down(offset, alignof_dword);
c5def85c
CW
1713 offset += I915_GTT_PAGE_SIZE;
1714
1715 err = write_to_scratch(ctx_a, engine,
1716 offset, 0xdeadbeef);
1717 if (err == 0)
1718 err = read_from_scratch(ctx_b, engine,
1719 offset, &value);
1720 if (err)
a4e7ccda 1721 goto out_file;
c5def85c
CW
1722
1723 if (value) {
1724 pr_err("%s: Read %08x from scratch (offset 0x%08x_%08x), after %lu reads!\n",
1725 engine->name, value,
1726 upper_32_bits(offset),
1727 lower_32_bits(offset),
1728 this);
1729 err = -EINVAL;
a4e7ccda 1730 goto out_file;
c5def85c
CW
1731 }
1732
1733 this++;
1734 }
1735 count += this;
1736 }
1737 pr_info("Checked %lu scratch offsets across %d engines\n",
8a68d464 1738 count, RUNTIME_INFO(i915)->num_engines);
c5def85c 1739
a4e7ccda 1740out_file:
e4a8c813 1741 if (igt_live_test_end(&t))
c5def85c 1742 err = -EIO;
c5def85c
CW
1743 mock_file_free(i915, file);
1744 return err;
1745}
1746
1fe2d6f9
CW
1747static bool skip_unused_engines(struct intel_context *ce, void *data)
1748{
1749 return !ce->state;
1750}
1751
85fddf0b
CW
1752static void mock_barrier_task(void *data)
1753{
1754 unsigned int *counter = data;
1755
1756 ++*counter;
1757}
1758
1759static int mock_context_barrier(void *arg)
1760{
1761#undef pr_fmt
1762#define pr_fmt(x) "context_barrier_task():" # x
1763 struct drm_i915_private *i915 = arg;
1764 struct i915_gem_context *ctx;
1765 struct i915_request *rq;
85fddf0b
CW
1766 unsigned int counter;
1767 int err;
1768
1769 /*
1770 * The context barrier provides us with a callback after it emits
1771 * a request; useful for retiring old state after loading new.
1772 */
1773
85fddf0b 1774 ctx = mock_context(i915, "mock");
a4e7ccda
CW
1775 if (!ctx)
1776 return -ENOMEM;
85fddf0b
CW
1777
1778 counter = 0;
e0695db7 1779 err = context_barrier_task(ctx, 0,
1fe2d6f9 1780 NULL, NULL, mock_barrier_task, &counter);
85fddf0b
CW
1781 if (err) {
1782 pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1783 goto out;
1784 }
1785 if (counter == 0) {
1786 pr_err("Did not retire immediately with 0 engines\n");
1787 err = -EINVAL;
1788 goto out;
1789 }
1790
1791 counter = 0;
e0695db7 1792 err = context_barrier_task(ctx, ALL_ENGINES,
1fe2d6f9
CW
1793 skip_unused_engines,
1794 NULL,
1795 mock_barrier_task,
1796 &counter);
85fddf0b
CW
1797 if (err) {
1798 pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1799 goto out;
1800 }
1801 if (counter == 0) {
62c8e423 1802 pr_err("Did not retire immediately for all unused engines\n");
85fddf0b
CW
1803 err = -EINVAL;
1804 goto out;
1805 }
1806
46472b3e 1807 rq = igt_request_alloc(ctx, i915->engine[RCS0]);
85fddf0b
CW
1808 if (IS_ERR(rq)) {
1809 pr_err("Request allocation failed!\n");
1810 goto out;
1811 }
1812 i915_request_add(rq);
85fddf0b
CW
1813
1814 counter = 0;
1815 context_barrier_inject_fault = BIT(RCS0);
e0695db7 1816 err = context_barrier_task(ctx, ALL_ENGINES,
1fe2d6f9 1817 NULL, NULL, mock_barrier_task, &counter);
85fddf0b
CW
1818 context_barrier_inject_fault = 0;
1819 if (err == -ENXIO)
1820 err = 0;
1821 else
1822 pr_err("Did not hit fault injection!\n");
1823 if (counter != 0) {
1824 pr_err("Invoked callback on error!\n");
1825 err = -EIO;
1826 }
1827 if (err)
1828 goto out;
1829
1830 counter = 0;
e0695db7 1831 err = context_barrier_task(ctx, ALL_ENGINES,
1fe2d6f9
CW
1832 skip_unused_engines,
1833 NULL,
1834 mock_barrier_task,
1835 &counter);
85fddf0b
CW
1836 if (err) {
1837 pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1838 goto out;
1839 }
1840 mock_device_flush(i915);
1841 if (counter == 0) {
1842 pr_err("Did not retire on each active engines\n");
1843 err = -EINVAL;
1844 goto out;
1845 }
1846
1847out:
1848 mock_context_close(ctx);
85fddf0b
CW
1849 return err;
1850#undef pr_fmt
1851#define pr_fmt(x) x
1852}
1853
09a4c02e
CW
1854int i915_gem_context_mock_selftests(void)
1855{
1856 static const struct i915_subtest tests[] = {
85fddf0b 1857 SUBTEST(mock_context_barrier),
09a4c02e
CW
1858 };
1859 struct drm_i915_private *i915;
1860 int err;
1861
1862 i915 = mock_gem_device();
1863 if (!i915)
1864 return -ENOMEM;
1865
1866 err = i915_subtests(tests, i915);
1867
a24362ea 1868 drm_dev_put(&i915->drm);
09a4c02e
CW
1869 return err;
1870}
1871
cb823ed9 1872int i915_gem_context_live_selftests(struct drm_i915_private *i915)
791ff39a
CW
1873{
1874 static const struct i915_subtest tests[] = {
a47cd45a 1875 SUBTEST(live_nop_switch),
50d16d44 1876 SUBTEST(live_parallel_switch),
791ff39a 1877 SUBTEST(igt_ctx_exec),
250f8c81 1878 SUBTEST(igt_ctx_readonly),
c06ee6ff 1879 SUBTEST(igt_ctx_sseu),
e0695db7 1880 SUBTEST(igt_shared_ctx_exec),
c5def85c 1881 SUBTEST(igt_vm_isolation),
791ff39a 1882 };
92fdf8d4 1883
cb823ed9 1884 if (intel_gt_is_wedged(&i915->gt))
31c9bd78
CW
1885 return 0;
1886
cb823ed9 1887 return i915_live_subtests(tests, i915);
791ff39a 1888}