s/drmtest_subtest_block/drmtest_subtest/
[platform/upstream/intel-gpu-tools.git] / tests / prime_nv_test.c
1 /* basic set of prime tests between intel and nouveau */
2
3 /* test list -
4    1. share buffer from intel -> nouveau.
5    2. share buffer from nouveau -> intel
6    3. share intel->nouveau, map on both, write intel, read nouveau
7    4. share intel->nouveau, blit intel fill, readback on nouveau
8    test 1 + map buffer, read/write, map other size.
9    do some hw actions on the buffer
10    some illegal operations -
11        close prime fd try and map
12
13    TODO add some nouveau rendering tests
14 */
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24
25 #include "i915_drm.h"
26 #include "intel_bufmgr.h"
27 #include "nouveau.h"
28 #include "intel_gpu_tools.h"
29 #include "intel_batchbuffer.h"
30 #include "drmtest.h"
31
32 int intel_fd = -1, nouveau_fd = -1;
33 drm_intel_bufmgr *bufmgr;
34 struct nouveau_device *ndev;
35 struct nouveau_client *nclient;
36 uint32_t devid;
37 struct intel_batchbuffer *intel_batch;
38
39 #define BO_SIZE (256*1024)
40
41 static int find_and_open_devices(void)
42 {
43         int i;
44         char path[80];
45         struct stat buf;
46         FILE *fl;
47         char vendor_id[8];
48         int venid;
49         for (i = 0; i < 9; i++) {
50                 char *ret;
51
52                 sprintf(path, "/sys/class/drm/card%d/device/vendor", i);
53                 if (stat(path, &buf))
54                         break;
55
56                 fl = fopen(path, "r");
57                 if (!fl)
58                         break;
59
60                 ret = fgets(vendor_id, 8, fl);
61                 assert(ret);
62                 fclose(fl);
63
64                 venid = strtoul(vendor_id, NULL, 16);
65                 sprintf(path, "/dev/dri/card%d", i);
66                 if (venid == 0x8086) {
67                         intel_fd = open(path, O_RDWR);
68                         if (!intel_fd)
69                                 return -1;
70                 } else if (venid == 0x10de) {
71                         nouveau_fd = open(path, O_RDWR);
72                         if (!nouveau_fd)
73                                 return -1;
74                 }
75         }
76         return 0;
77 }
78
79 /*
80  * prime test 1 -
81  * allocate buffer on intel,
82  * set prime on buffer,
83  * retrive buffer from nouveau,
84  * close prime_fd,
85  *  unref buffers
86  */
87 static int test_i915_nv_sharing(void)
88 {
89         int ret;
90         drm_intel_bo *test_intel_bo;
91         int prime_fd;
92         struct nouveau_bo *nvbo;
93
94         test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
95
96         drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
97
98         ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
99         close(prime_fd);
100         if (ret < 0)
101                 return ret;
102
103         nouveau_bo_ref(NULL, &nvbo);
104         drm_intel_bo_unreference(test_intel_bo);
105         return 0;
106 }
107
108 /*
109  * prime test 2 -
110  * allocate buffer on nouveau
111  * set prime on buffer,
112  * retrive buffer from intel
113  * close prime_fd,
114  *  unref buffers
115  */
116 static int test_nv_i915_sharing(void)
117 {
118         int ret;
119         drm_intel_bo *test_intel_bo;
120         int prime_fd;
121         struct nouveau_bo *nvbo;
122
123         ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
124                              0, BO_SIZE, NULL, &nvbo);
125         if (ret < 0)
126                 return ret;
127         ret = nouveau_bo_set_prime(nvbo, &prime_fd);
128         if (ret < 0)
129                 return ret;
130
131         test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
132         close(prime_fd);
133         if (!test_intel_bo)
134                 return -1;
135
136         nouveau_bo_ref(NULL, &nvbo);
137         drm_intel_bo_unreference(test_intel_bo);
138         return 0;
139 }
140
141 /*
142  * allocate intel, give to nouveau, map on nouveau
143  * write 0xdeadbeef, non-gtt map on intel, read
144  */
145 static int test_nv_write_i915_cpu_mmap_read(void)
146 {
147         int ret;
148         drm_intel_bo *test_intel_bo;
149         int prime_fd;
150         struct nouveau_bo *nvbo = NULL;
151         uint32_t *ptr;
152
153         test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
154
155         drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
156
157         ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
158         if (ret < 0) {
159                 fprintf(stderr,"failed to ref prime buffer %d\n", ret);
160                 close(prime_fd);
161                 goto free_intel;
162         }
163         close(prime_fd);
164                 goto free_intel;
165
166         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
167         if (ret < 0) {
168                 fprintf(stderr,"failed to map nouveau bo\n");
169                 goto out;
170         }
171
172         ptr = nvbo->map;
173         *ptr = 0xdeadbeef;
174
175         drm_intel_bo_map(test_intel_bo, 1);
176
177         ptr = test_intel_bo->virtual;
178
179         if (*ptr != 0xdeadbeef) {
180                 fprintf(stderr,"mapped value doesn't match\n");
181                 ret = -1;
182         }
183 out:
184         nouveau_bo_ref(NULL, &nvbo);
185 free_intel:
186         drm_intel_bo_unreference(test_intel_bo);
187         return ret;
188 }
189
190 /*
191  * allocate intel, give to nouveau, map on nouveau
192  * write 0xdeadbeef, gtt map on intel, read
193  */
194 static int test_nv_write_i915_gtt_mmap_read(void)
195 {
196         int ret;
197         drm_intel_bo *test_intel_bo;
198         int prime_fd;
199         struct nouveau_bo *nvbo = NULL;
200         uint32_t *ptr;
201
202         test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
203
204         drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
205
206         ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
207         close(prime_fd);
208         if (ret < 0) {
209                 fprintf(stderr,"failed to ref prime buffer\n");
210                 return ret;
211         }
212
213         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
214         if (ret < 0) {
215                 fprintf(stderr,"failed to map nouveau bo\n");
216                 goto out;
217         }
218
219
220         ptr = nvbo->map;
221         *ptr = 0xdeadbeef;
222
223         drm_intel_gem_bo_map_gtt(test_intel_bo);
224         ptr = test_intel_bo->virtual;
225
226         if (*ptr != 0xdeadbeef) {
227                 fprintf(stderr,"mapped value doesn't match\n");
228                 ret = -1;
229         }
230 out:
231         nouveau_bo_ref(NULL, &nvbo);
232         drm_intel_bo_unreference(test_intel_bo);
233         return ret;
234 }
235
236 /* test drm_intel_bo_map doesn't work properly,
237    this tries to map the backing shmem fd, which doesn't exist
238    for these objects */
239 static int test_i915_import_cpu_mmap(void)
240 {
241         int ret;
242         drm_intel_bo *test_intel_bo;
243         int prime_fd;
244         struct nouveau_bo *nvbo;
245         uint32_t *ptr;
246
247         ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
248                              0, BO_SIZE, NULL, &nvbo);
249         if (ret < 0)
250                 return ret;
251         ret = nouveau_bo_set_prime(nvbo, &prime_fd);
252         if (ret < 0)
253                 return ret;
254
255         test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
256         close(prime_fd);
257         if (!test_intel_bo)
258                 return -1;
259
260         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
261         if (ret < 0) {
262                 fprintf(stderr,"failed to map nouveau bo\n");
263                 goto out;
264         }
265
266         ptr = nvbo->map;
267         *ptr = 0xdeadbeef;
268
269         ret = drm_intel_bo_map(test_intel_bo, 0);
270         if (ret != 0) {
271                 fprintf(stderr,"failed to map imported bo on intel side\n");
272                 goto out;
273         }
274         if (!test_intel_bo->virtual) {
275                 ret = 0;
276                 goto out;
277         }
278         ptr = test_intel_bo->virtual;
279
280         if (*ptr != 0xdeadbeef) {
281                 fprintf(stderr,"mapped value doesn't match %08x\n", *ptr);
282                 ret = -1;
283         }
284  out:
285         nouveau_bo_ref(NULL, &nvbo);
286         drm_intel_bo_unreference(test_intel_bo);
287         return ret;
288 }
289
290 /* test drm_intel_bo_map_gtt works properly,
291    this tries to map the backing shmem fd, which doesn't exist
292    for these objects */
293 static int test_i915_import_gtt_mmap(void)
294 {
295         int ret;
296         drm_intel_bo *test_intel_bo;
297         int prime_fd;
298         struct nouveau_bo *nvbo;
299         uint32_t *ptr;
300
301         ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
302                              0, BO_SIZE, NULL, &nvbo);
303         if (ret < 0)
304                 return ret;
305         ret = nouveau_bo_set_prime(nvbo, &prime_fd);
306         if (ret < 0)
307                 return ret;
308
309         test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
310         close(prime_fd);
311         if (!test_intel_bo)
312                 return -1;
313
314         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
315         if (ret < 0) {
316                 fprintf(stderr,"failed to map nouveau bo\n");
317                 goto out;
318         }
319
320         ptr = nvbo->map;
321         *ptr = 0xdeadbeef;
322         *(ptr + 1) = 0xa55a55;
323
324         ret = drm_intel_gem_bo_map_gtt(test_intel_bo);
325         if (ret != 0) {
326                 fprintf(stderr,"failed to map bo\n");
327                 goto out;
328         }
329         if (!test_intel_bo->virtual) {
330                 ret = -1;
331                 fprintf(stderr,"failed to map bo\n");
332                 goto out;
333         }
334         ptr = test_intel_bo->virtual;
335
336         if (*ptr != 0xdeadbeef) {
337                 fprintf(stderr,"mapped value doesn't match %08x %08x\n", *ptr, *(ptr + 1));
338                 ret = -1;
339         }
340  out:
341         nouveau_bo_ref(NULL, &nvbo);
342         drm_intel_bo_unreference(test_intel_bo);
343         return ret;
344 }
345
346 /* test 7 - import from nouveau into intel, test pread/pwrite fail */
347 static int test_i915_import_pread_pwrite(void)
348 {
349         int ret;
350         drm_intel_bo *test_intel_bo;
351         int prime_fd;
352         struct nouveau_bo *nvbo;
353         uint32_t *ptr;
354         uint32_t buf[64];
355
356         ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
357                              0, BO_SIZE, NULL, &nvbo);
358         if (ret < 0)
359                 return ret;
360         ret = nouveau_bo_set_prime(nvbo, &prime_fd);
361         if (ret < 0)
362                 return ret;
363
364         test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
365         close(prime_fd);
366         if (!test_intel_bo)
367                 return -1;
368
369         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
370         if (ret < 0) {
371                 fprintf(stderr,"failed to map nouveau bo\n");
372                 goto out;
373         }
374
375         ptr = nvbo->map;
376         *ptr = 0xdeadbeef;
377
378         gem_read(intel_fd, test_intel_bo->handle, 0, buf, 256);
379         buf[0] = 0xabcdef55;
380
381         gem_write(intel_fd, test_intel_bo->handle, 0, buf, 4);
382  out:
383         nouveau_bo_ref(NULL, &nvbo);
384         drm_intel_bo_unreference(test_intel_bo);
385         return ret;
386 }
387
388 static void
389 set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
390 {
391         int size = width * height;
392         uint32_t *vaddr;
393
394         drm_intel_gem_bo_start_gtt_access(bo, true);
395         vaddr = bo->virtual;
396         while (size--)
397                 *vaddr++ = val;
398 }
399
400 static drm_intel_bo *
401 create_bo(drm_intel_bufmgr *ibufmgr, uint32_t val, int width, int height)
402 {
403         drm_intel_bo *bo;
404
405         bo = drm_intel_bo_alloc(ibufmgr, "bo", 4*width*height, 0);
406         assert(bo);
407
408         /* gtt map doesn't have a write parameter, so just keep the mapping
409          * around (to avoid the set_domain with the gtt write domain set) and
410          * manually tell the kernel when we start access the gtt. */
411         drm_intel_gem_bo_map_gtt(bo);
412
413         set_bo(bo, val, width, height);
414
415         return bo;
416 }
417
418 /* use intel hw to fill the BO with a blit from another BO,
419    then readback from the nouveau bo, check value is correct */
420 static int test_i915_blt_fill_nv_read(void)
421 {
422         int ret;
423         drm_intel_bo *test_intel_bo, *src_bo;
424         int prime_fd;
425         struct nouveau_bo *nvbo = NULL;
426         uint32_t *ptr;
427
428         src_bo = create_bo(bufmgr, 0xaa55aa55, 256, 1);
429
430         test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
431
432         drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
433
434         ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
435         close(prime_fd);
436         if (ret < 0) {
437                 fprintf(stderr,"failed to ref prime buffer\n");
438                 return ret;
439         }
440
441         intel_copy_bo(intel_batch, test_intel_bo, src_bo, 256, 1);
442
443         ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
444         if (ret < 0) {
445                 fprintf(stderr,"failed to map nouveau bo\n");
446                 goto out;
447         }
448
449         drm_intel_bo_map(test_intel_bo, 0);
450
451         ptr = nvbo->map;
452         if (*ptr != 0xaa55aa55) {
453                 fprintf(stderr,"mapped value doesn't match\n");
454                 ret = -1;
455         }
456 out:
457         nouveau_bo_ref(NULL, &nvbo);
458         drm_intel_bo_unreference(test_intel_bo);
459         return ret;
460 }
461
462 /* test 8 use nouveau to do blit */
463
464 /* test 9 nouveau copy engine?? */
465
466 int main(int argc, char **argv)
467 {
468         int ret = 0;
469
470         ret = find_and_open_devices();
471         if (ret < 0)
472                 return ret;
473
474         drmtest_subtest_init(argc, argv);
475
476         if (nouveau_fd == -1 || intel_fd == -1) {
477                 fprintf(stderr,"failed to find intel and nouveau GPU\n");
478                 if (!drmtest_only_list_subtests())
479                         return 77;
480         }
481
482         /* set up intel bufmgr */
483         bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096);
484         if (!bufmgr)
485                 return -1;
486         /* Do not enable reuse, we share (almost) all buffers. */
487         //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
488
489         /* set up nouveau bufmgr */
490         ret = nouveau_device_wrap(nouveau_fd, 0, &ndev);
491         if (ret < 0) {
492                 fprintf(stderr,"failed to wrap nouveau device\n");
493                 return 77;
494         }
495
496         ret = nouveau_client_new(ndev, &nclient);
497         if (ret < 0) {
498                 fprintf(stderr,"failed to setup nouveau client\n");
499                 return -1;
500         }
501
502         /* set up an intel batch buffer */
503         devid = intel_get_drm_devid(intel_fd);
504         intel_batch = intel_batchbuffer_alloc(bufmgr, devid);
505
506 #define xtest(name) \
507         drmtest_subtest(#name) \
508                 if (test_##name()) \
509                         exit(2);
510
511         xtest(i915_nv_sharing);
512         xtest(nv_i915_sharing);
513         xtest(nv_write_i915_cpu_mmap_read);
514         xtest(nv_write_i915_gtt_mmap_read);
515         xtest(i915_import_cpu_mmap);
516         xtest(i915_import_gtt_mmap);
517         xtest(i915_import_pread_pwrite);
518         xtest(i915_blt_fill_nv_read);
519
520         intel_batchbuffer_free(intel_batch);
521
522         nouveau_device_del(&ndev);
523         drm_intel_bufmgr_destroy(bufmgr);
524
525         close(intel_fd);
526         close(nouveau_fd);
527
528         return ret;
529 }