blob: a1abc67cdd2bc7a4623db32396649a68e416cae9 [file] [log] [blame]
Chris Wilson51e965f2016-01-17 16:21:01 +00001/*
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#include <time.h>
Chris Wilson3ef69132016-07-05 15:40:44 +010025#include <pthread.h>
Chris Wilson51e965f2016-01-17 16:21:01 +000026
27#include "igt.h"
Chris Wilsonc6e26e42016-07-22 12:58:54 +010028#include "igt_sysfs.h"
Chris Wilson51e965f2016-01-17 16:21:01 +000029
Chris Wilsond2c61962016-07-04 12:37:32 +010030#define LOCAL_I915_EXEC_NO_RELOC (1<<11)
31#define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
32
33#define LOCAL_I915_EXEC_BSD_SHIFT (13)
34#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT)
35
36#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
37
Chris Wilson51e965f2016-01-17 16:21:01 +000038IGT_TEST_DESCRIPTION("Basic check of ring<->ring write synchronisation.");
39
40/*
41 * Testcase: Basic check of sync
42 *
43 * Extremely efficient at catching missed irqs
44 */
45
Chris Wilson51e965f2016-01-17 16:21:01 +000046static double gettime(void)
47{
48 static clockid_t clock = -1;
49 struct timespec ts;
50
51 /* Stay on the same clock for consistency. */
52 if (clock != (clockid_t)-1) {
53 if (clock_gettime(clock, &ts))
54 goto error;
55 goto out;
56 }
57
58#ifdef CLOCK_MONOTONIC_RAW
59 if (!clock_gettime(clock = CLOCK_MONOTONIC_RAW, &ts))
60 goto out;
61#endif
62#ifdef CLOCK_MONOTONIC_COARSE
63 if (!clock_gettime(clock = CLOCK_MONOTONIC_COARSE, &ts))
64 goto out;
65#endif
66 if (!clock_gettime(clock = CLOCK_MONOTONIC, &ts))
67 goto out;
68error:
69 igt_warn("Could not read monotonic time: %s\n",
70 strerror(errno));
71 igt_assert(0);
72 return 0;
73
74out:
75 return ts.tv_sec + 1e-9*ts.tv_nsec;
76}
77
Chris Wilsond2c61962016-07-04 12:37:32 +010078static bool can_mi_store_dword(int gen, unsigned engine)
79{
Chris Wilsonee6a40f2017-02-03 21:57:33 +000080 return gen > 2 && !(gen == 6 && (engine & ~(3<<13)) == I915_EXEC_BSD);
Chris Wilsond2c61962016-07-04 12:37:32 +010081}
82
Chris Wilson51e965f2016-01-17 16:21:01 +000083static void
Chris Wilson69b29f82016-10-18 10:23:49 +010084sync_ring(int fd, unsigned ring, int num_children, int timeout)
Chris Wilson51e965f2016-01-17 16:21:01 +000085{
Chris Wilson43043952016-02-26 10:06:51 +000086 unsigned engines[16];
87 const char *names[16];
88 int num_engines = 0;
Chris Wilson51e965f2016-01-17 16:21:01 +000089
Chris Wilson43043952016-02-26 10:06:51 +000090 if (ring == ~0u) {
91 const struct intel_execution_engine *e;
92
93 for (e = intel_execution_engines; e->name; e++) {
94 if (e->exec_id == 0)
95 continue;
96
Chris Wilson3fd9b912016-03-25 20:27:34 +000097 if (!gem_has_ring(fd, e->exec_id | e->flags))
Chris Wilson43043952016-02-26 10:06:51 +000098 continue;
99
100 if (e->exec_id == I915_EXEC_BSD) {
101 int is_bsd2 = e->flags != 0;
102 if (gem_has_bsd2(fd) != is_bsd2)
103 continue;
104 }
105
106 names[num_engines] = e->name;
107 engines[num_engines++] = e->exec_id | e->flags;
108 if (num_engines == ARRAY_SIZE(engines))
109 break;
110 }
111
112 num_children *= num_engines;
113 } else {
114 gem_require_ring(fd, ring);
115 names[num_engines] = NULL;
116 engines[num_engines++] = ring;
117 }
118
119 intel_detect_and_clear_missed_interrupts(fd);
Chris Wilson0667cf52016-02-26 09:09:51 +0000120 igt_fork(child, num_children) {
121 const uint32_t bbe = MI_BATCH_BUFFER_END;
Chris Wilson0667cf52016-02-26 09:09:51 +0000122 struct drm_i915_gem_exec_object2 object;
Chris Wilson43043952016-02-26 10:06:51 +0000123 struct drm_i915_gem_execbuffer2 execbuf;
Chris Wilson0667cf52016-02-26 09:09:51 +0000124 double start, elapsed;
125 unsigned long cycles;
Chris Wilson51e965f2016-01-17 16:21:01 +0000126
Chris Wilson0667cf52016-02-26 09:09:51 +0000127 memset(&object, 0, sizeof(object));
128 object.handle = gem_create(fd, 4096);
129 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
Chris Wilson51e965f2016-01-17 16:21:01 +0000130
Chris Wilson0667cf52016-02-26 09:09:51 +0000131 memset(&execbuf, 0, sizeof(execbuf));
Chris Wilson4de67b22017-01-02 11:05:21 +0000132 execbuf.buffers_ptr = to_user_pointer(&object);
Chris Wilson0667cf52016-02-26 09:09:51 +0000133 execbuf.buffer_count = 1;
Chris Wilson43043952016-02-26 10:06:51 +0000134 execbuf.flags = engines[child % num_engines];
Chris Wilson51e965f2016-01-17 16:21:01 +0000135 gem_execbuf(fd, &execbuf);
Chris Wilson51e965f2016-01-17 16:21:01 +0000136
Chris Wilson0667cf52016-02-26 09:09:51 +0000137 start = gettime();
138 cycles = 0;
139 do {
140 do {
141 gem_execbuf(fd, &execbuf);
142 gem_sync(fd, object.handle);
143 } while (++cycles & 1023);
Chris Wilson69b29f82016-10-18 10:23:49 +0100144 } while ((elapsed = gettime() - start) < timeout);
Chris Wilson43043952016-02-26 10:06:51 +0000145 igt_info("%s%sompleted %ld cycles: %.3f us\n",
146 names[child % num_engines] ?: "",
147 names[child % num_engines] ? " c" : "C",
148 cycles, elapsed*1e6/cycles);
Chris Wilson0667cf52016-02-26 09:09:51 +0000149
150 gem_close(fd, object.handle);
151 }
Chris Wilson69b29f82016-10-18 10:23:49 +0100152 igt_waitchildren_timeout(timeout+10, NULL);
Chris Wilson5b675f72016-01-22 17:33:40 +0000153 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
Chris Wilson51e965f2016-01-17 16:21:01 +0000154}
155
Chris Wilson3fd9b912016-03-25 20:27:34 +0000156static void
Chris Wilson69b29f82016-10-18 10:23:49 +0100157store_ring(int fd, unsigned ring, int num_children, int timeout)
Chris Wilsond2c61962016-07-04 12:37:32 +0100158{
159 const int gen = intel_gen(intel_get_drm_devid(fd));
160 unsigned engines[16];
161 const char *names[16];
162 int num_engines = 0;
163
164 if (ring == ~0u) {
165 const struct intel_execution_engine *e;
166
167 for (e = intel_execution_engines; e->name; e++) {
168 if (e->exec_id == 0)
169 continue;
170
171 if (!gem_has_ring(fd, e->exec_id | e->flags))
172 continue;
173
174 if (!can_mi_store_dword(gen, e->exec_id))
175 continue;
176
177 if (e->exec_id == I915_EXEC_BSD) {
178 int is_bsd2 = e->flags != 0;
179 if (gem_has_bsd2(fd) != is_bsd2)
180 continue;
181 }
182
183 names[num_engines] = e->name;
184 engines[num_engines++] = e->exec_id | e->flags;
185 if (num_engines == ARRAY_SIZE(engines))
186 break;
187 }
188
189 num_children *= num_engines;
190 } else {
191 gem_require_ring(fd, ring);
Chris Wilson3ef69132016-07-05 15:40:44 +0100192 igt_require(can_mi_store_dword(gen, ring));
Chris Wilsond2c61962016-07-04 12:37:32 +0100193 names[num_engines] = NULL;
194 engines[num_engines++] = ring;
195 }
196
197 intel_detect_and_clear_missed_interrupts(fd);
198 igt_fork(child, num_children) {
199 const uint32_t bbe = MI_BATCH_BUFFER_END;
200 struct drm_i915_gem_exec_object2 object[2];
201 struct drm_i915_gem_relocation_entry reloc[1024];
202 struct drm_i915_gem_execbuffer2 execbuf;
203 double start, elapsed;
204 unsigned long cycles;
205 uint32_t *batch, *b;
206
207 memset(&execbuf, 0, sizeof(execbuf));
Chris Wilson4de67b22017-01-02 11:05:21 +0000208 execbuf.buffers_ptr = to_user_pointer(object);
Chris Wilsond2c61962016-07-04 12:37:32 +0100209 execbuf.flags = engines[child % num_engines];
210 execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
211 execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
212 if (gen < 6)
213 execbuf.flags |= I915_EXEC_SECURE;
214
215 memset(object, 0, sizeof(object));
216 object[0].handle = gem_create(fd, 4096);
217 gem_write(fd, object[0].handle, 0, &bbe, sizeof(bbe));
218 execbuf.buffer_count = 1;
219 gem_execbuf(fd, &execbuf);
220
221 object[0].flags |= EXEC_OBJECT_WRITE;
222 object[1].handle = gem_create(fd, 20*1024);
223
Chris Wilson4de67b22017-01-02 11:05:21 +0000224 object[1].relocs_ptr = to_user_pointer(reloc);
Chris Wilsond2c61962016-07-04 12:37:32 +0100225 object[1].relocation_count = 1024;
226
227 batch = gem_mmap__cpu(fd, object[1].handle, 0, 20*1024,
228 PROT_WRITE | PROT_READ);
229 gem_set_domain(fd, object[1].handle,
230 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
231
232 memset(reloc, 0, sizeof(reloc));
233 b = batch;
234 for (int i = 0; i < 1024; i++) {
235 uint64_t offset;
236
237 reloc[i].presumed_offset = object[0].offset;
238 reloc[i].offset = (b - batch + 1) * sizeof(*batch);
239 reloc[i].delta = i * sizeof(uint32_t);
240 reloc[i].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
241 reloc[i].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
242
243 offset = object[0].offset + reloc[i].delta;
244 *b++ = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
245 if (gen >= 8) {
246 *b++ = offset;
247 *b++ = offset >> 32;
248 } else if (gen >= 4) {
249 *b++ = 0;
250 *b++ = offset;
251 reloc[i].offset += sizeof(*batch);
252 } else {
253 b[-1] -= 1;
254 *b++ = offset;
255 }
256 *b++ = i;
257 }
258 *b++ = MI_BATCH_BUFFER_END;
259 igt_assert((b - batch)*sizeof(uint32_t) < 20*1024);
260 munmap(batch, 20*1024);
261 execbuf.buffer_count = 2;
262 gem_execbuf(fd, &execbuf);
263 gem_sync(fd, object[1].handle);
264
265 start = gettime();
266 cycles = 0;
267 do {
268 do {
269 gem_execbuf(fd, &execbuf);
270 gem_sync(fd, object[1].handle);
271 } while (++cycles & 1023);
Chris Wilson69b29f82016-10-18 10:23:49 +0100272 } while ((elapsed = gettime() - start) < timeout);
Chris Wilsond2c61962016-07-04 12:37:32 +0100273 igt_info("%s%sompleted %ld cycles: %.3f us\n",
274 names[child % num_engines] ?: "",
275 names[child % num_engines] ? " c" : "C",
276 cycles, elapsed*1e6/cycles);
277
278 gem_close(fd, object[1].handle);
279 gem_close(fd, object[0].handle);
280 }
Chris Wilson69b29f82016-10-18 10:23:49 +0100281 igt_waitchildren_timeout(timeout+10, NULL);
Chris Wilsond2c61962016-07-04 12:37:32 +0100282 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
283}
284
Chris Wilson3ef69132016-07-05 15:40:44 +0100285static void xchg(void *array, unsigned i, unsigned j)
286{
287 uint32_t *u32 = array;
288 uint32_t tmp = u32[i];
289 u32[i] = u32[j];
290 u32[j] = tmp;
291}
292
293struct waiter {
294 pthread_t thread;
295 pthread_mutex_t mutex;
296 pthread_cond_t cond;
297
298 int ready;
299 volatile int *done;
300
301 int fd;
302 struct drm_i915_gem_exec_object2 object;
303 uint32_t handles[64];
304};
305
306static void *waiter(void *arg)
307{
308 struct waiter *w = arg;
309
310 do {
311 pthread_mutex_lock(&w->mutex);
312 w->ready = 0;
313 pthread_cond_signal(&w->cond);
314 while (!w->ready)
315 pthread_cond_wait(&w->cond, &w->mutex);
316 pthread_mutex_unlock(&w->mutex);
317 if (*w->done < 0)
318 return NULL;
319
320 gem_sync(w->fd, w->object.handle);
321 for (int n = 0; n < ARRAY_SIZE(w->handles); n++)
322 gem_sync(w->fd, w->handles[n]);
323 } while (1);
324}
325
326static void
327__store_many(int fd, unsigned ring, int timeout, unsigned long *cycles)
328{
329 const int gen = intel_gen(intel_get_drm_devid(fd));
330 const uint32_t bbe = MI_BATCH_BUFFER_END;
331 struct drm_i915_gem_exec_object2 object[2];
332 struct drm_i915_gem_execbuffer2 execbuf;
333 struct drm_i915_gem_relocation_entry reloc[1024];
334 struct waiter threads[64];
335 int order[64];
336 uint32_t *batch, *b;
337 int done;
338
339 memset(&execbuf, 0, sizeof(execbuf));
Chris Wilson4de67b22017-01-02 11:05:21 +0000340 execbuf.buffers_ptr = to_user_pointer(object);
Chris Wilson3ef69132016-07-05 15:40:44 +0100341 execbuf.flags = ring;
342 execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
343 execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
344 if (gen < 6)
345 execbuf.flags |= I915_EXEC_SECURE;
346
347 memset(object, 0, sizeof(object));
348 object[0].handle = gem_create(fd, 4096);
349 gem_write(fd, object[0].handle, 0, &bbe, sizeof(bbe));
350 execbuf.buffer_count = 1;
351 gem_execbuf(fd, &execbuf);
352 object[0].flags |= EXEC_OBJECT_WRITE;
353
Chris Wilson4de67b22017-01-02 11:05:21 +0000354 object[1].relocs_ptr = to_user_pointer(reloc);
Chris Wilson3ef69132016-07-05 15:40:44 +0100355 object[1].relocation_count = 1024;
356 execbuf.buffer_count = 2;
357
358 memset(reloc, 0, sizeof(reloc));
359 b = batch = malloc(20*1024);
360 for (int i = 0; i < 1024; i++) {
361 uint64_t offset;
362
363 reloc[i].presumed_offset = object[0].offset;
364 reloc[i].offset = (b - batch + 1) * sizeof(*batch);
365 reloc[i].delta = i * sizeof(uint32_t);
366 reloc[i].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
367 reloc[i].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
368
369 offset = object[0].offset + reloc[i].delta;
370 *b++ = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
371 if (gen >= 8) {
372 *b++ = offset;
373 *b++ = offset >> 32;
374 } else if (gen >= 4) {
375 *b++ = 0;
376 *b++ = offset;
377 reloc[i].offset += sizeof(*batch);
378 } else {
379 b[-1] -= 1;
380 *b++ = offset;
381 }
382 *b++ = i;
383 }
384 *b++ = MI_BATCH_BUFFER_END;
385 igt_assert((b - batch)*sizeof(uint32_t) < 20*1024);
386
387 done = 0;
388 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
389 threads[i].fd = fd;
390 threads[i].object = object[1];
391 threads[i].object.handle = gem_create(fd, 20*1024);
392 gem_write(fd, threads[i].object.handle, 0, batch, 20*1024);
393
394 pthread_cond_init(&threads[i].cond, NULL);
395 pthread_mutex_init(&threads[i].mutex, NULL);
396 threads[i].done = &done;
397 threads[i].ready = 0;
398
399 pthread_create(&threads[i].thread, NULL, waiter, &threads[i]);
400 order[i] = i;
401 }
402 free(batch);
403
404 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
405 for (int j = 0; j < ARRAY_SIZE(threads); j++)
406 threads[i].handles[j] = threads[j].object.handle;
407 }
408
409 igt_until_timeout(timeout) {
410 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
411 pthread_mutex_lock(&threads[i].mutex);
412 while (threads[i].ready)
413 pthread_cond_wait(&threads[i].cond,
414 &threads[i].mutex);
415 pthread_mutex_unlock(&threads[i].mutex);
416 igt_permute_array(threads[i].handles,
417 ARRAY_SIZE(threads[i].handles),
418 xchg);
419 }
420
421 igt_permute_array(order, ARRAY_SIZE(threads), xchg);
422 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
423 object[1] = threads[i].object;
424 gem_execbuf(fd, &execbuf);
425 threads[i].object = object[1];
426 }
427 ++*cycles;
428
429 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
430 struct waiter *w = &threads[order[i]];
431
432 w->ready = 1;
433 pthread_cond_signal(&w->cond);
434 }
435 }
436
437 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
438 pthread_mutex_lock(&threads[i].mutex);
439 while (threads[i].ready)
440 pthread_cond_wait(&threads[i].cond, &threads[i].mutex);
441 pthread_mutex_unlock(&threads[i].mutex);
442 }
443 done = -1;
444 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
445 threads[i].ready = 1;
446 pthread_cond_signal(&threads[i].cond);
447 pthread_join(threads[i].thread, NULL);
448 gem_close(fd, threads[i].object.handle);
449 }
450
451 gem_close(fd, object[0].handle);
452}
453
454static void
455store_many(int fd, unsigned ring, int timeout)
456{
457 const int gen = intel_gen(intel_get_drm_devid(fd));
458 unsigned long *shared;
459 const char *names[16];
Chris Wilsona2880c72016-07-06 09:27:00 +0100460 int n = 0;
Chris Wilson3ef69132016-07-05 15:40:44 +0100461
462 shared = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
463 igt_assert(shared != MAP_FAILED);
464
465 intel_detect_and_clear_missed_interrupts(fd);
466
467 if (ring == ~0u) {
468 const struct intel_execution_engine *e;
469
470 for (e = intel_execution_engines; e->name; e++) {
471 if (e->exec_id == 0)
472 continue;
473
474 if (!gem_has_ring(fd, e->exec_id | e->flags))
475 continue;
476
477 if (!can_mi_store_dword(gen, e->exec_id))
478 continue;
479
480 if (e->exec_id == I915_EXEC_BSD) {
481 int is_bsd2 = e->flags != 0;
482 if (gem_has_bsd2(fd) != is_bsd2)
483 continue;
484 }
485
486 igt_fork(child, 1)
487 __store_many(fd,
488 e->exec_id | e->flags,
489 timeout,
490 &shared[n]);
491
492 names[n++] = e->name;
493 }
494 igt_waitchildren();
495 } else {
496 gem_require_ring(fd, ring);
497 igt_require(can_mi_store_dword(gen, ring));
Chris Wilson2202b062016-07-05 21:28:21 +0100498 __store_many(fd, ring, timeout, &shared[n]);
499 names[n++] = NULL;
Chris Wilson3ef69132016-07-05 15:40:44 +0100500 }
501
502 for (int i = 0; i < n; i++) {
503 igt_info("%s%sompleted %ld cycles\n",
504 names[i] ?: "", names[i] ? " c" : "C", shared[i]);
505 }
506 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
Chris Wilson2202b062016-07-05 21:28:21 +0100507 munmap(shared, 4096);
Chris Wilson3ef69132016-07-05 15:40:44 +0100508}
509
Chris Wilsond2c61962016-07-04 12:37:32 +0100510static void
Chris Wilson69b29f82016-10-18 10:23:49 +0100511sync_all(int fd, int num_children, int timeout)
Chris Wilson3fd9b912016-03-25 20:27:34 +0000512{
513 const struct intel_execution_engine *e;
514 unsigned engines[16];
515 int num_engines = 0;
516
517 for (e = intel_execution_engines; e->name; e++) {
518 if (e->exec_id == 0)
519 continue;
520
521 if (!gem_has_ring(fd, e->exec_id | e->flags))
522 continue;
523
524 if (e->exec_id == I915_EXEC_BSD) {
525 int is_bsd2 = e->flags != 0;
526 if (gem_has_bsd2(fd) != is_bsd2)
527 continue;
528 }
529
530 engines[num_engines++] = e->exec_id | e->flags;
531 if (num_engines == ARRAY_SIZE(engines))
532 break;
533 }
534 igt_require(num_engines);
535
536 intel_detect_and_clear_missed_interrupts(fd);
537 igt_fork(child, num_children) {
538 const uint32_t bbe = MI_BATCH_BUFFER_END;
539 struct drm_i915_gem_exec_object2 object;
540 struct drm_i915_gem_execbuffer2 execbuf;
541 double start, elapsed;
542 unsigned long cycles;
543
544 memset(&object, 0, sizeof(object));
545 object.handle = gem_create(fd, 4096);
546 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
547
548 memset(&execbuf, 0, sizeof(execbuf));
Chris Wilson4de67b22017-01-02 11:05:21 +0000549 execbuf.buffers_ptr = to_user_pointer(&object);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000550 execbuf.buffer_count = 1;
551 gem_execbuf(fd, &execbuf);
552
553 start = gettime();
554 cycles = 0;
555 do {
556 do {
557 for (int n = 0; n < num_engines; n++) {
558 execbuf.flags = engines[n];
559 gem_execbuf(fd, &execbuf);
560 }
561 gem_sync(fd, object.handle);
562 } while (++cycles & 1023);
Chris Wilson69b29f82016-10-18 10:23:49 +0100563 } while ((elapsed = gettime() - start) < timeout);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000564 igt_info("Completed %ld cycles: %.3f us\n",
565 cycles, elapsed*1e6/cycles);
566
567 gem_close(fd, object.handle);
568 }
Chris Wilson69b29f82016-10-18 10:23:49 +0100569 igt_waitchildren_timeout(timeout+10, NULL);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000570 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
571}
572
Chris Wilsond2c61962016-07-04 12:37:32 +0100573static void
Chris Wilson69b29f82016-10-18 10:23:49 +0100574store_all(int fd, int num_children, int timeout)
Chris Wilsond2c61962016-07-04 12:37:32 +0100575{
576 const int gen = intel_gen(intel_get_drm_devid(fd));
577 const struct intel_execution_engine *e;
578 unsigned engines[16];
579 int num_engines = 0;
580
581 for (e = intel_execution_engines; e->name; e++) {
582 if (e->exec_id == 0)
583 continue;
584
585 if (!gem_has_ring(fd, e->exec_id | e->flags))
586 continue;
587
588 if (!can_mi_store_dword(gen, e->exec_id))
589 continue;
590
591 if (e->exec_id == I915_EXEC_BSD) {
592 int is_bsd2 = e->flags != 0;
593 if (gem_has_bsd2(fd) != is_bsd2)
594 continue;
595 }
596
597 engines[num_engines++] = e->exec_id | e->flags;
598 if (num_engines == ARRAY_SIZE(engines))
599 break;
600 }
601 igt_require(num_engines);
602
603 intel_detect_and_clear_missed_interrupts(fd);
604 igt_fork(child, num_children) {
605 const uint32_t bbe = MI_BATCH_BUFFER_END;
606 struct drm_i915_gem_exec_object2 object[2];
607 struct drm_i915_gem_relocation_entry reloc[1024];
608 struct drm_i915_gem_execbuffer2 execbuf;
609 double start, elapsed;
610 unsigned long cycles;
611 uint32_t *batch, *b;
612
613 memset(&execbuf, 0, sizeof(execbuf));
Chris Wilson4de67b22017-01-02 11:05:21 +0000614 execbuf.buffers_ptr = to_user_pointer(object);
Chris Wilsond2c61962016-07-04 12:37:32 +0100615 execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
616 execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
617 if (gen < 6)
618 execbuf.flags |= I915_EXEC_SECURE;
619
620 memset(object, 0, sizeof(object));
621 object[0].handle = gem_create(fd, 4096);
622 gem_write(fd, object[0].handle, 0, &bbe, sizeof(bbe));
623 execbuf.buffer_count = 1;
624 gem_execbuf(fd, &execbuf);
625
626 object[0].flags |= EXEC_OBJECT_WRITE;
627 object[1].handle = gem_create(fd, 1024*16 + 4096);
628
Chris Wilson4de67b22017-01-02 11:05:21 +0000629 object[1].relocs_ptr = to_user_pointer(reloc);
Chris Wilsond2c61962016-07-04 12:37:32 +0100630 object[1].relocation_count = 1024;
631
632 batch = gem_mmap__cpu(fd, object[1].handle, 0, 16*1024 + 4096,
633 PROT_WRITE | PROT_READ);
634 gem_set_domain(fd, object[1].handle,
635 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
636
637 memset(reloc, 0, sizeof(reloc));
638 b = batch;
639 for (int i = 0; i < 1024; i++) {
640 uint64_t offset;
641
642 reloc[i].presumed_offset = object[0].offset;
643 reloc[i].offset = (b - batch + 1) * sizeof(*batch);
644 reloc[i].delta = i * sizeof(uint32_t);
645 reloc[i].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
646 reloc[i].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
647
648 offset = object[0].offset + reloc[i].delta;
649 *b++ = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
650 if (gen >= 8) {
651 *b++ = offset;
652 *b++ = offset >> 32;
653 } else if (gen >= 4) {
654 *b++ = 0;
655 *b++ = offset;
656 reloc[i].offset += sizeof(*batch);
657 } else {
658 b[-1] -= 1;
659 *b++ = offset;
660 }
661 *b++ = i;
662 }
663 *b++ = MI_BATCH_BUFFER_END;
664 igt_assert((b - batch)*sizeof(uint32_t) < 20*1024);
665 munmap(batch, 16*1024+4096);
666 execbuf.buffer_count = 2;
667 gem_execbuf(fd, &execbuf);
668 gem_sync(fd, object[1].handle);
669
670 start = gettime();
671 cycles = 0;
672 do {
673 do {
674 igt_permute_array(engines, num_engines, xchg);
675 for (int n = 0; n < num_engines; n++) {
676 execbuf.flags &= ~ENGINE_MASK;
677 execbuf.flags |= engines[n];
678 gem_execbuf(fd, &execbuf);
679 }
680 gem_sync(fd, object[1].handle);
681 } while (++cycles & 1023);
Chris Wilson69b29f82016-10-18 10:23:49 +0100682 } while ((elapsed = gettime() - start) < timeout);
Chris Wilsond2c61962016-07-04 12:37:32 +0100683 igt_info("Completed %ld cycles: %.3f us\n",
684 cycles, elapsed*1e6/cycles);
685
686 gem_close(fd, object[1].handle);
687 gem_close(fd, object[0].handle);
688 }
Chris Wilson69b29f82016-10-18 10:23:49 +0100689 igt_waitchildren_timeout(timeout+10, NULL);
Chris Wilsond2c61962016-07-04 12:37:32 +0100690 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
691}
692
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100693static void print_welcome(int fd)
694{
695 bool active;
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100696 int dir;
697
698 dir = igt_sysfs_open_parameters(fd);
699 if (dir < 0)
700 return;
701
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100702 active = igt_sysfs_get_boolean(dir, "enable_guc_submission");
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100703 if (active) {
704 igt_info("Using GuC submission\n");
705 goto out;
706 }
707
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100708 active = igt_sysfs_get_boolean(dir, "enable_execlists");
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100709 if (active) {
710 igt_info("Using Execlists submission\n");
711 goto out;
712 }
713
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100714 active = igt_sysfs_get_boolean(dir, "semaphores");
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100715 igt_info("Using Legacy submission %s\n",
716 active ? ", with semaphores" : "");
717
718out:
719 close(dir);
720}
721
Chris Wilson51e965f2016-01-17 16:21:01 +0000722igt_main
723{
Chris Wilsond1308992016-01-27 14:17:53 +0000724 const struct intel_execution_engine *e;
Chris Wilson43043952016-02-26 10:06:51 +0000725 const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
Chris Wilson51e965f2016-01-17 16:21:01 +0000726 int fd = -1;
727
728 igt_skip_on_simulation();
729
Daniel Vetterbe21fc02016-06-17 16:04:09 +0200730 igt_fixture {
Chris Wilson51e965f2016-01-17 16:21:01 +0000731 fd = drm_open_driver(DRIVER_INTEL);
Chris Wilson9518cb52017-02-22 15:24:54 +0000732 igt_require_gem(fd);
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100733 print_welcome(fd);
Chris Wilson51e965f2016-01-17 16:21:01 +0000734
Daniel Vetterbe21fc02016-06-17 16:04:09 +0200735 igt_fork_hang_detector(fd);
736 }
Chris Wilson9d61a682016-03-25 18:22:54 +0000737
Chris Wilson0667cf52016-02-26 09:09:51 +0000738 for (e = intel_execution_engines; e->name; e++) {
Chris Wilsonfbf5edb2016-05-20 11:19:17 +0100739 igt_subtest_f("%s", e->name)
Chris Wilson69b29f82016-10-18 10:23:49 +0100740 sync_ring(fd, e->exec_id | e->flags, 1, 150);
Chris Wilsond2c61962016-07-04 12:37:32 +0100741 igt_subtest_f("store-%s", e->name)
Chris Wilson69b29f82016-10-18 10:23:49 +0100742 store_ring(fd, e->exec_id | e->flags, 1, 150);
Chris Wilson3ef69132016-07-05 15:40:44 +0100743 igt_subtest_f("many-%s", e->name)
Chris Wilson69b29f82016-10-18 10:23:49 +0100744 store_many(fd, e->exec_id | e->flags, 150);
Chris Wilson0667cf52016-02-26 09:09:51 +0000745 igt_subtest_f("forked-%s", e->name)
Chris Wilson69b29f82016-10-18 10:23:49 +0100746 sync_ring(fd, e->exec_id | e->flags, ncpus, 150);
Chris Wilsond2c61962016-07-04 12:37:32 +0100747 igt_subtest_f("forked-store-%s", e->name)
Chris Wilson69b29f82016-10-18 10:23:49 +0100748 store_ring(fd, e->exec_id | e->flags, ncpus, 150);
Chris Wilson0667cf52016-02-26 09:09:51 +0000749 }
Chris Wilson51e965f2016-01-17 16:21:01 +0000750
Chris Wilson3fd9b912016-03-25 20:27:34 +0000751 igt_subtest("basic-each")
Chris Wilson69b29f82016-10-18 10:23:49 +0100752 sync_ring(fd, ~0u, 1, 5);
Chris Wilson76541f42016-08-23 16:51:38 +0100753 igt_subtest("basic-store-each")
Chris Wilson69b29f82016-10-18 10:23:49 +0100754 store_ring(fd, ~0u, 1, 5);
Chris Wilson3ef69132016-07-05 15:40:44 +0100755 igt_subtest("basic-many-each")
Chris Wilson69b29f82016-10-18 10:23:49 +0100756 store_many(fd, ~0u, 5);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000757 igt_subtest("forked-each")
Chris Wilson69b29f82016-10-18 10:23:49 +0100758 sync_ring(fd, ~0u, ncpus, 150);
Chris Wilsond2c61962016-07-04 12:37:32 +0100759 igt_subtest("forked-store-each")
Chris Wilson69b29f82016-10-18 10:23:49 +0100760 store_ring(fd, ~0u, ncpus, 150);
Chris Wilson43043952016-02-26 10:06:51 +0000761
Chris Wilson3fd9b912016-03-25 20:27:34 +0000762 igt_subtest("basic-all")
Chris Wilson69b29f82016-10-18 10:23:49 +0100763 sync_all(fd, 1, 5);
Chris Wilsond2c61962016-07-04 12:37:32 +0100764 igt_subtest("basic-store-all")
Chris Wilson69b29f82016-10-18 10:23:49 +0100765 store_all(fd, 1, 5);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000766 igt_subtest("forked-all")
Chris Wilson69b29f82016-10-18 10:23:49 +0100767 sync_all(fd, ncpus, 150);
Chris Wilsond2c61962016-07-04 12:37:32 +0100768 igt_subtest("forked-store-all")
Chris Wilson69b29f82016-10-18 10:23:49 +0100769 store_all(fd, ncpus, 150);
Chris Wilson3fd9b912016-03-25 20:27:34 +0000770
Daniel Vetterbe21fc02016-06-17 16:04:09 +0200771 igt_fixture {
772 igt_stop_hang_detector();
Chris Wilson51e965f2016-01-17 16:21:01 +0000773 close(fd);
Daniel Vetterbe21fc02016-06-17 16:04:09 +0200774 }
Chris Wilson51e965f2016-01-17 16:21:01 +0000775}