lib/igt_kms: Unify pipe name helpers
[platform/upstream/intel-gpu-tools.git] / tests / kms_fence_pin_leak.c
1 /*
2  * Copyright © 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "drmtest.h"
32 #include "igt_debugfs.h"
33 #include "igt_kms.h"
34 #include "ioctl_wrappers.h"
35 #include "intel_chipset.h"
36
37 typedef struct {
38         int drm_fd;
39         uint32_t devid;
40         drm_intel_bufmgr *bufmgr;
41         igt_display_t display;
42         drm_intel_bo *bos[64]; /* >= num fence registers */
43 } data_t;
44
45 static void exec_nop(data_t *data, uint32_t handle, drm_intel_context *context)
46 {
47         drm_intel_bo *dst;
48         struct intel_batchbuffer *batch;
49
50         dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
51         igt_assert(dst);
52
53         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
54         igt_assert(batch);
55
56         /* add the reloc to make sure the kernel will think we write to dst */
57         BEGIN_BATCH(4);
58         OUT_BATCH(MI_BATCH_BUFFER_END);
59         OUT_BATCH(MI_NOOP);
60         OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
61         OUT_BATCH(MI_NOOP);
62         ADVANCE_BATCH();
63
64         intel_batchbuffer_flush_with_context(batch, context);
65         intel_batchbuffer_free(batch);
66
67         drm_intel_bo_unreference(dst);
68 }
69
70 static void alloc_fence_objs(data_t *data)
71 {
72         int i;
73
74         for (i = 0; i < ARRAY_SIZE(data->bos); i++) {
75                 drm_intel_bo *bo;
76
77                 bo = drm_intel_bo_alloc(data->bufmgr, "fence bo", 4096, 4096);
78                 igt_assert(bo);
79                 gem_set_tiling(data->drm_fd, bo->handle, I915_TILING_X, 512);
80
81                 data->bos[i] = bo;
82         }
83 }
84
85 static void touch_fences(data_t *data)
86 {
87         int i;
88
89         for (i = 0; i < ARRAY_SIZE(data->bos); i++) {
90                 uint32_t handle = data->bos[i]->handle;
91                 void *ptr;
92
93                 ptr = gem_mmap__gtt(data->drm_fd, handle, 4096, PROT_WRITE);
94                 gem_set_domain(data->drm_fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
95                 memset(ptr, 0, 4);
96                 munmap(ptr, 4096);
97         }
98 }
99
100 static void free_fence_objs(data_t *data)
101 {
102         int i;
103
104         for (i = 0; i < ARRAY_SIZE(data->bos); i++)
105                 drm_intel_bo_unreference(data->bos[i]);
106 }
107
108 static bool run_single_test(data_t *data, enum pipe pipe, igt_output_t *output)
109 {
110         igt_display_t *display = &data->display;
111         drmModeModeInfo *mode;
112         igt_plane_t *primary;
113         struct igt_fb fb[2];
114         int i;
115
116         igt_output_set_pipe(output, pipe);
117         igt_display_commit(display);
118
119         if (!output->valid) {
120                 igt_output_set_pipe(output, PIPE_ANY);
121                 igt_display_commit(display);
122                 return false;
123         }
124
125         mode = igt_output_get_mode(output);
126         primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
127
128         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
129                             DRM_FORMAT_XRGB8888,
130                             true, /* need a fence so must be tiled */
131                             0.0, 0.0, 0.0,
132                             &fb[0]);
133         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
134                             DRM_FORMAT_XRGB8888,
135                             true, /* need a fence so must be tiled */
136                             0.0, 0.0, 0.0,
137                             &fb[1]);
138
139         igt_plane_set_fb(primary, &fb[0]);
140         igt_display_commit(display);
141
142         for (i = 0; i < 64; i++) {
143                 drm_intel_context *ctx;
144
145                 /*
146                  * Link fb.gem_handle to the ppgtt vm of ctx so that the context
147                  * destruction will unbind the obj from the ppgtt vm in question.
148                  */
149                 ctx = drm_intel_gem_context_create(data->bufmgr);
150                 igt_assert(ctx);
151                 exec_nop(data, fb[i&1].gem_handle, ctx);
152                 drm_intel_gem_context_destroy(ctx);
153
154                 /* Force a context switch to make sure ctx gets destroyed for real. */
155                 exec_nop(data, fb[i&1].gem_handle, NULL);
156
157                 gem_sync(data->drm_fd, fb[i&1].gem_handle);
158
159                 /*
160                  * Make only the current fb has a fence and
161                  * the next fb will pick a new fence. Assuming
162                  * all fences are associated with an object, the
163                  * kernel will always pick a fence with pin_count==0.
164                  */
165                 touch_fences(data);
166
167                 /*
168                  * Pin the new buffer and unpin the old buffer from display. If
169                  * the kernel is buggy the ppgtt unbind will have dropped the
170                  * fence for the old buffer, and now the display code will try
171                  * to unpin only to find no fence there. So the pin_count will leak.
172                  */
173                 igt_plane_set_fb(primary, &fb[!(i&1)]);
174                 igt_display_commit(display);
175
176                 igt_info(".");
177                 fflush(stdout);
178         }
179
180         igt_plane_set_fb(primary, NULL);
181         igt_output_set_pipe(output, PIPE_ANY);
182         igt_display_commit(display);
183
184         igt_remove_fb(data->drm_fd, &fb[1]);
185         igt_remove_fb(data->drm_fd, &fb[0]);
186
187         igt_info("\n");
188
189         return true;
190 }
191
192 static void run_test(data_t *data)
193 {
194         igt_display_t *display = &data->display;
195         igt_output_t *output;
196         enum pipe p;
197
198         for_each_connected_output(display, output) {
199                 for_each_pipe(display, p) {
200                         if (run_single_test(data, p, output))
201                                 return; /* one time ought to be enough */
202                 }
203         }
204
205         igt_skip("no valid crtc/connector combinations found\n");
206 }
207
208 igt_simple_main
209 {
210         drm_intel_context *ctx;
211         data_t data = {};
212
213         igt_skip_on_simulation();
214
215         data.drm_fd = drm_open_any();
216
217         data.devid = intel_get_drm_devid(data.drm_fd);
218
219         igt_set_vt_graphics_mode();
220
221         data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
222         igt_assert(data.bufmgr);
223         drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);
224
225         igt_display_init(&data.display, data.drm_fd);
226
227         ctx = drm_intel_gem_context_create(data.bufmgr);
228         igt_require(ctx);
229         drm_intel_gem_context_destroy(ctx);
230
231         alloc_fence_objs(&data);
232
233         run_test(&data);
234
235         free_fence_objs(&data);
236
237         drm_intel_bufmgr_destroy(data.bufmgr);
238         igt_display_fini(&data.display);
239 }