lib: rename intel_gpu_tools.h to intel_io.h
[platform/upstream/intel-gpu-tools.git] / tests / gem_seqno_wrap.c
1 /*
2  * Copyright (c) 2012 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  * Authors:
24  *    Mika Kuoppala <mika.kuoppala@intel.com>
25  *
26  */
27
28 /*
29  * This test runs blitcopy -> rendercopy with multiple buffers over wrap
30  * boundary.
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <limits.h>
41 #include <wordexp.h>
42 #include <getopt.h>
43 #include <signal.h>
44 #include <errno.h>
45
46 #include "ioctl_wrappers.h"
47 #include "drmtest.h"
48 #include "igt_core.h"
49 #include "intel_bufmgr.h"
50 #include "intel_batchbuffer.h"
51 #include "intel_io.h"
52 #include "intel_chipset.h"
53
54 static int devid;
55 static int card_index = 0;
56 static uint32_t last_seqno = 0;
57
58 static struct intel_batchbuffer *batch_blt;
59 static struct intel_batchbuffer *batch_3d;
60
61 struct option_struct {
62         int rounds;
63         int background;
64         char cmd[1024];
65         int timeout;
66         int dontwrap;
67         int prewrap_space;
68         int random;
69         int buffers;
70 };
71
72 static struct option_struct options;
73
74 static void init_buffer(drm_intel_bufmgr *bufmgr,
75                         struct igt_buf *buf,
76                         drm_intel_bo *bo,
77                         int width, int height)
78 {
79         /* buf->bo = drm_intel_bo_alloc(bufmgr, "", size, 4096); */
80         buf->bo = bo;
81         buf->size = width * height * 4;
82         igt_assert(buf->bo);
83         buf->tiling = I915_TILING_NONE;
84         buf->num_tiles = width * height * 4;
85         buf->stride = width * 4;
86 }
87
88 static void
89 set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
90 {
91         int size = width * height;
92         uint32_t *vaddr;
93
94         drm_intel_gem_bo_start_gtt_access(bo, true);
95         vaddr = bo->virtual;
96         while (size--)
97                 *vaddr++ = val;
98 }
99
100 static int
101 cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
102 {
103         int size = width * height;
104         uint32_t *vaddr;
105
106         drm_intel_gem_bo_start_gtt_access(bo, false);
107         vaddr = bo->virtual;
108         while (size--) {
109                 if (*vaddr++ != val) {
110                         printf("%d: 0x%x differs from assumed 0x%x\n",
111                                width * height - size, *vaddr-1, val);
112                         return -1;
113                 }
114         }
115
116         return 0;
117 }
118
119 static drm_intel_bo *
120 create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
121 {
122         drm_intel_bo *bo;
123
124         bo = drm_intel_bo_alloc(bufmgr, "bo", width * height * 4, 0);
125         igt_assert(bo);
126
127         /* gtt map doesn't have a write parameter, so just keep the mapping
128          * around (to avoid the set_domain with the gtt write domain set) and
129          * manually tell the kernel when we start access the gtt. */
130         drm_intel_gem_bo_map_gtt(bo);
131
132         set_bo(bo, val, width, height);
133
134         return bo;
135 }
136
137 static void release_bo(drm_intel_bo *bo)
138 {
139         drm_intel_gem_bo_unmap_gtt(bo);
140         drm_intel_bo_unreference(bo);
141 }
142
143 static void render_copyfunc(struct igt_buf *src,
144                             struct igt_buf *dst,
145                             int width,
146                             int height)
147 {
148         const int src_x = 0, src_y = 0, dst_x = 0, dst_y = 0;
149         igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
150         static int warned = 0;
151
152         if (rendercopy) {
153                 rendercopy(batch_3d, NULL,
154                            src, src_x, src_y,
155                            width, height,
156                            dst, dst_x, dst_y);
157                 intel_batchbuffer_flush(batch_3d);
158         } else {
159                 if (!warned) {
160                         printf("No render copy found for this gen, "
161                                "test is shallow!\n");
162                         warned = 1;
163                 }
164                 igt_assert(dst->bo);
165                 igt_assert(src->bo);
166                 intel_copy_bo(batch_blt, dst->bo, src->bo, width*height*4);
167                 intel_batchbuffer_flush(batch_blt);
168         }
169 }
170
171 static void exchange_uint(void *array, unsigned i, unsigned j)
172 {
173         unsigned *i_arr = array;
174         unsigned i_tmp;
175
176         i_tmp = i_arr[i];
177         i_arr[i] = i_arr[j];
178         i_arr[j] = i_tmp;
179 }
180
181 static int run_sync_test(int num_buffers, bool verify)
182 {
183         drm_intel_bufmgr *bufmgr;
184         int max;
185         drm_intel_bo **src, **dst1, **dst2;
186         int width = 128, height = 128;
187         int fd;
188         int i;
189         int r = -1;
190         int failed = 0;
191         unsigned int *p_dst1, *p_dst2;
192         struct igt_buf *s_src, *s_dst;
193
194         fd = drm_open_any();
195         igt_assert(fd >= 0);
196
197         gem_quiescent_gpu(fd);
198
199         devid = intel_get_drm_devid(fd);
200
201         max = gem_aperture_size (fd) / (1024 * 1024) / 2;
202         if (num_buffers > max)
203                 num_buffers = max;
204
205         bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
206         drm_intel_bufmgr_gem_enable_reuse(bufmgr);
207         batch_blt = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
208         igt_assert(batch_blt);
209         batch_3d = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
210         igt_assert(batch_3d);
211
212         src = malloc(num_buffers * sizeof(*src));
213         igt_assert(src);
214
215         dst1 = malloc(num_buffers * sizeof(*dst1));
216         igt_assert(dst1);
217
218         dst2 = malloc(num_buffers * sizeof(*dst2));
219         igt_assert(dst2);
220
221         s_src = malloc(num_buffers * sizeof(*s_src));
222         igt_assert(s_src);
223
224         s_dst = malloc(num_buffers * sizeof(*s_dst));
225         igt_assert(s_dst);
226
227         p_dst1 = malloc(num_buffers * sizeof(unsigned int));
228         if (p_dst1 == NULL)
229                 return -ENOMEM;
230
231         p_dst2 = malloc(num_buffers * sizeof(unsigned int));
232         if (p_dst2 == NULL)
233                 return -ENOMEM;
234
235         for (i = 0; i < num_buffers; i++) {
236                 p_dst1[i] = p_dst2[i] = i;
237                 src[i] = create_bo(bufmgr, i, width, height);
238                 igt_assert(src[i]);
239                 dst1[i] = create_bo(bufmgr, ~i, width, height);
240                 igt_assert(dst1[i]);
241                 dst2[i] = create_bo(bufmgr, ~i, width, height);
242                 igt_assert(dst2[i]);
243                 init_buffer(bufmgr, &s_src[i], src[i], width, height);
244                 init_buffer(bufmgr, &s_dst[i], dst1[i], width, height);
245         }
246
247         igt_permute_array(p_dst1, num_buffers, exchange_uint);
248         igt_permute_array(p_dst2, num_buffers, exchange_uint);
249
250         for (i = 0; i < num_buffers; i++)
251                 render_copyfunc(&s_src[i], &s_dst[p_dst1[i]], width, height);
252
253         /* Only sync between buffers if this is actual test run and
254          * not a seqno filler */
255         if (verify) {
256                 for (i = 0; i < num_buffers; i++)
257                         intel_copy_bo(batch_blt, dst2[p_dst2[i]], dst1[p_dst1[i]],
258                                       width*height*4);
259
260                 for (i = 0; i < num_buffers; i++) {
261                         r = cmp_bo(dst2[p_dst2[i]], i, width, height);
262                         if (r) {
263                                 printf("buffer %d differs, seqno_before_test 0x%x, "
264                                        " approximated seqno on test fail 0x%x\n",
265                                        i, last_seqno, last_seqno + i * 2);
266                                 failed = -1;
267                         }
268                 }
269         }
270
271         for (i = 0; i < num_buffers; i++) {
272                 release_bo(src[i]);
273                 release_bo(dst1[i]);
274                 release_bo(dst2[i]);
275         }
276
277         intel_batchbuffer_free(batch_3d);
278         intel_batchbuffer_free(batch_blt);
279         drm_intel_bufmgr_destroy(bufmgr);
280
281         free(p_dst1);
282         free(p_dst2);
283         free(s_dst);
284         free(s_src);
285         free(dst2);
286         free(dst1);
287         free(src);
288
289         gem_quiescent_gpu(fd);
290
291         close(fd);
292
293         return failed;
294 }
295
296 static int run_cmd(char *s)
297 {
298         int pid;
299         int r = -1;
300         int status = 0;
301         wordexp_t wexp;
302         int i;
303         r = wordexp(s, &wexp, 0);
304         if (r != 0) {
305                 printf("can't parse %s\n", s);
306                 return r;
307         }
308
309         for(i = 0; i < wexp.we_wordc; i++)
310                 printf("argv[%d] = %s\n", i, wexp.we_wordv[i]);
311
312         pid = fork();
313
314         if (pid == 0) {
315                 char path[PATH_MAX];
316                 char full_path[PATH_MAX];
317
318                 if (getcwd(path, PATH_MAX) == NULL)
319                         perror("getcwd");
320
321                 igt_assert(snprintf(full_path, PATH_MAX, "%s/%s", path, wexp.we_wordv[0]) > 0);
322
323                 r = execv(full_path, wexp.we_wordv);
324                 if (r == -1)
325                         perror("execv failed");
326         } else {
327                 int waitcount = options.timeout;
328
329                 while(waitcount-- > 0) {
330                         r = waitpid(pid, &status, WNOHANG);
331                         if (r == pid) {
332                                 if(WIFEXITED(status)) {
333                                         if (WEXITSTATUS(status))
334                                                 fprintf(stderr,
335                                                     "child returned with %d\n",
336                                                         WEXITSTATUS(status));
337                                         return WEXITSTATUS(status);
338                                 }
339                         } else if (r != 0) {
340                                 perror("waitpid");
341                                 return -errno;
342                         }
343
344                         sleep(3);
345                 }
346
347                 kill(pid, SIGKILL);
348                 return -ETIMEDOUT;
349         }
350
351         return r;
352 }
353
354 static const char *dfs_base = "/sys/kernel/debug/dri";
355 static const char *dfs_entry = "i915_next_seqno";
356
357 static int dfs_open(int mode)
358 {
359         char fname[FILENAME_MAX];
360         int fh;
361
362         snprintf(fname, FILENAME_MAX, "%s/%i/%s",
363                  dfs_base, card_index, dfs_entry);
364
365         fh = open(fname, mode);
366         igt_require(fh >= 0);
367
368         return fh;
369 }
370
371 static int __read_seqno(uint32_t *seqno)
372 {
373         int fh;
374         char buf[32];
375         int r;
376         char *p;
377         unsigned long int tmp;
378
379         fh = dfs_open(O_RDONLY);
380
381         r = read(fh, buf, sizeof(buf) - 1);
382         close(fh);
383         if (r < 0) {
384                 perror("read");
385                 return -errno;
386         }
387
388         buf[r] = 0;
389
390         p = strstr(buf, "0x");
391         if (!p)
392                 p = buf;
393
394         errno = 0;
395         tmp = strtoul(p, NULL, 0);
396         if (tmp == ULONG_MAX && errno) {
397                 perror("strtoul");
398                 return -errno;
399         }
400
401         *seqno = tmp;
402
403         igt_debug("next_seqno: 0x%x\n", *seqno);
404
405         return 0;
406 }
407
408 static int read_seqno(void)
409 {
410         uint32_t seqno = 0;
411         int r;
412         int wrap = 0;
413
414         r = __read_seqno(&seqno);
415         igt_assert(r == 0);
416
417         if (last_seqno > seqno)
418                 wrap++;
419
420         last_seqno = seqno;
421
422         return wrap;
423 }
424
425 static int write_seqno(uint32_t seqno)
426 {
427         int fh;
428         char buf[32];
429         int r;
430         uint32_t rb;
431
432         if (options.dontwrap)
433                 return 0;
434
435         fh = dfs_open(O_RDWR);
436         igt_assert(snprintf(buf, sizeof(buf), "0x%x", seqno) > 0);
437
438         r = write(fh, buf, strnlen(buf, sizeof(buf)));
439         close(fh);
440         if (r < 0)
441                 return r;
442
443         igt_assert(r == strnlen(buf, sizeof(buf)));
444
445         last_seqno = seqno;
446
447         igt_debug("next_seqno set to: 0x%x\n", seqno);
448
449         r = __read_seqno(&rb);
450         if (r < 0)
451                 return r;
452
453         if (rb != seqno) {
454                 printf("seqno readback differs rb:0x%x vs w:0x%x\n", rb, seqno);
455                 return -1;
456         }
457
458         return 0;
459 }
460
461 static uint32_t calc_prewrap_val(void)
462 {
463         const int pval = options.prewrap_space;
464
465         if (options.random == 0)
466                 return pval;
467
468         if (pval == 0)
469                 return 0;
470
471         return (random() % pval);
472 }
473
474 static int run_test(void)
475 {
476         int r;
477
478         if (strnlen(options.cmd, sizeof(options.cmd)) > 0) {
479                 r = run_cmd(options.cmd);
480         } else {
481                 r = run_sync_test(options.buffers, true);
482         }
483
484         return r;
485 }
486
487 static void preset_run_once(void)
488 {
489         igt_assert(write_seqno(1) == 0);
490         igt_assert(run_test() == 0);
491
492         igt_assert(write_seqno(0x7fffffff) == 0);
493         igt_assert(run_test() == 0);
494
495         igt_assert(write_seqno(0xffffffff) == 0);
496         igt_assert(run_test() == 0);
497
498         igt_assert(write_seqno(0xfffffff0) == 0);
499         igt_assert(run_test() == 0);
500 }
501
502 static void random_run_once(void)
503 {
504         uint32_t val;
505
506         do {
507                 val = random() % UINT32_MAX;
508                 if (RAND_MAX < UINT32_MAX)
509                         val += random();
510         } while (val == 0);
511
512         igt_assert(write_seqno(val) == 0);
513         igt_assert(run_test() == 0);
514 }
515
516 static void wrap_run_once(void)
517 {
518         const uint32_t pw_val = calc_prewrap_val();
519
520         igt_assert(write_seqno(UINT32_MAX - pw_val) == 0);
521
522         while(!read_seqno())
523                 igt_assert(run_test() == 0);
524 }
525
526 static void background_run_once(void)
527 {
528         const uint32_t pw_val = calc_prewrap_val();
529
530         igt_assert(write_seqno(UINT32_MAX - pw_val) == 0);
531
532         while(!read_seqno())
533                 sleep(3);
534 }
535
536 static void print_usage(const char *s)
537 {
538         printf("%s: [OPTION]...\n", s);
539         printf("    where options are:\n");
540         printf("    -b --background       run in background inducing wraps\n");
541         printf("    -c --cmd=cmdstring    use cmdstring to cross wrap\n");
542         printf("    -n --rounds=num       run num times across wrap boundary, 0 == forever\n");
543         printf("    -t --timeout=sec      set timeout to wait for testrun to sec seconds\n");
544         printf("    -d --dontwrap         don't wrap just run the test\n");
545         printf("    -p --prewrap=n        set seqno to WRAP - n for each testrun\n");
546         printf("    -r --norandom         dont randomize prewrap space\n");
547         printf("    -i --buffers          number of buffers to copy\n");
548         igt_fail(-1);
549 }
550
551 static void parse_options(int argc, char **argv)
552 {
553         int c;
554         int option_index = 0;
555         static struct option long_options[] = {
556                 {"cmd", required_argument, 0, 'c'},
557                 {"rounds", required_argument, 0, 'n'},
558                 {"background", no_argument, 0, 'b'},
559                 {"timeout", required_argument, 0, 't'},
560                 {"dontwrap", no_argument, 0, 'd'},
561                 {"prewrap", required_argument, 0, 'p'},
562                 {"norandom", no_argument, 0, 'r'},
563                 {"buffers", required_argument, 0, 'i'},
564         };
565
566         strcpy(options.cmd, "");
567         options.rounds = SLOW_QUICK(50, 2);
568         options.background = 0;
569         options.dontwrap = 0;
570         options.timeout = 20;
571         options.random = 1;
572         options.prewrap_space = 21;
573         options.buffers = 10;
574
575         while((c = getopt_long(argc, argv, "c:n:bvt:dp:ri:",
576                                long_options, &option_index)) != -1) {
577                 switch(c) {
578                 case 'b':
579                         options.background = 1;
580                         printf("running in background inducing wraps\n");
581                         break;
582                 case 'd':
583                         options.dontwrap = 1;
584                         printf("won't wrap after testruns\n");
585                         break;
586                 case 'n':
587                         options.rounds = atoi(optarg);
588                         printf("running %d rounds\n", options.rounds);
589                         break;
590                 case 'c':
591                         strncpy(options.cmd, optarg, sizeof(options.cmd) - 1);
592                         options.cmd[sizeof(options.cmd) - 1] = 0;
593                         printf("cmd set to %s\n", options.cmd);
594                         break;
595                 case 'i':
596                         options.buffers = atoi(optarg);
597                         printf("buffers %d\n", options.buffers);
598                         break;
599                 case 't':
600                         options.timeout = atoi(optarg);
601                         if (options.timeout == 0)
602                                 options.timeout = 10;
603                         printf("setting timeout to %d seconds\n",
604                                options.timeout);
605                         break;
606                 case 'r':
607                         options.random = 0;
608                         break;
609                 case 'p':
610                         options.prewrap_space = atoi(optarg);
611                         printf("prewrap set to %d (0x%x)\n",
612                                options.prewrap_space, UINT32_MAX -
613                                options.prewrap_space);
614                         break;
615                 default:
616                         printf("unkown command options\n");
617                         print_usage(argv[0]);
618                         break;
619                 }
620         }
621
622         if (optind < argc) {
623                 printf("unkown command options\n");
624                 print_usage(argv[0]);
625         }
626 }
627
628 int main(int argc, char **argv)
629 {
630         int wcount = 0;
631         int r = -1;
632
633         igt_simple_init();
634
635         parse_options(argc, argv);
636
637         card_index = drm_get_card();
638
639         srandom(time(NULL));
640
641         while(options.rounds == 0 || wcount < options.rounds) {
642                 if (options.background) {
643                         background_run_once();
644                 } else {
645                         preset_run_once();
646                         random_run_once();
647                         wrap_run_once();
648                 }
649
650                 wcount++;
651
652                 igt_debug("%s done: %d\n",
653                           options.dontwrap ? "tests" : "wraps", wcount);
654         }
655
656         if (options.rounds == wcount) {
657                 igt_debug("done %d wraps successfully\n", wcount);
658                 return 0;
659         }
660
661         return r;
662 }