1 /*
2 * Copyright © 2011 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 * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c)
25 *
26 */
27
28 /*
29 * Testcase: (TLB-)Coherency of pipe_control QW writes
30 *
31 * Writes a counter-value into an always newly allocated target bo (by disabling
32 * buffer reuse). Decently trashes on tlb inconsistencies, too.
33 */
34 #include "igt.h"
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <inttypes.h>
40 #include <errno.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include "drm.h"
44 #include "intel_bufmgr.h"
45
46 IGT_TEST_DESCRIPTION("Test (TLB-)Coherency of pipe_control QW writes.");
47
48 static drm_intel_bufmgr *bufmgr;
49 struct intel_batchbuffer *batch;
50 uint32_t devid;
51
52 #define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
53 #define PIPE_CONTROL_WRITE_IMMEDIATE (1<<14)
54 #define PIPE_CONTROL_WRITE_TIMESTAMP (3<<14)
55 #define PIPE_CONTROL_DEPTH_STALL (1<<13)
56 #define PIPE_CONTROL_WC_FLUSH (1<<12)
57 #define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
58 #define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
59 #define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1)
60 #define PIPE_CONTROL_CS_STALL (1<<20)
61 #define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
62
63 /* Like the store dword test, but we create new command buffers each time */
64 static void
store_pipe_control_loop(bool preuse_buffer)65 store_pipe_control_loop(bool preuse_buffer)
66 {
67 int i, val = 0;
68 uint32_t *buf;
69 drm_intel_bo *target_bo;
70
71 for (i = 0; i < SLOW_QUICK(0x10000, 4); i++) {
72 /* we want to check tlb consistency of the pipe_control target,
73 * so get a new buffer every time around */
74 target_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
75 igt_assert(target_bo);
76
77 if (preuse_buffer) {
78 COLOR_BLIT_COPY_BATCH_START(0);
79 OUT_BATCH((3 << 24) | (0xf0 << 16) | 64);
80 OUT_BATCH(0);
81 OUT_BATCH(1 << 16 | 1);
82
83 /*
84 * IMPORTANT: We need to preuse the buffer in a
85 * different domain than what the pipe control write
86 * (and kernel wa) uses!
87 */
88 OUT_RELOC_FENCED(target_bo,
89 I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
90 0);
91 OUT_BATCH(0xdeadbeef);
92 ADVANCE_BATCH();
93
94 intel_batchbuffer_flush(batch);
95 }
96
97 /* gem_storedw_batches_loop.c is a bit overenthusiastic with
98 * creating new batchbuffers - with buffer reuse disabled, the
99 * support code will do that for us. */
100 if (batch->gen >= 8) {
101 BEGIN_BATCH(4, 1);
102 OUT_BATCH(GFX_OP_PIPE_CONTROL + 1);
103 OUT_BATCH(PIPE_CONTROL_WRITE_IMMEDIATE);
104 OUT_RELOC_FENCED(target_bo,
105 I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
106 PIPE_CONTROL_GLOBAL_GTT);
107 OUT_BATCH(val); /* write data */
108 ADVANCE_BATCH();
109
110 } else if (batch->gen >= 6) {
111 /* work-around hw issue, see intel_emit_post_sync_nonzero_flush
112 * in mesa sources. */
113 BEGIN_BATCH(4, 1);
114 OUT_BATCH(GFX_OP_PIPE_CONTROL);
115 OUT_BATCH(PIPE_CONTROL_CS_STALL |
116 PIPE_CONTROL_STALL_AT_SCOREBOARD);
117 OUT_BATCH(0); /* address */
118 OUT_BATCH(0); /* write data */
119 ADVANCE_BATCH();
120
121 BEGIN_BATCH(4, 1);
122 OUT_BATCH(GFX_OP_PIPE_CONTROL);
123 OUT_BATCH(PIPE_CONTROL_WRITE_IMMEDIATE);
124 OUT_RELOC(target_bo,
125 I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
126 PIPE_CONTROL_GLOBAL_GTT);
127 OUT_BATCH(val); /* write data */
128 ADVANCE_BATCH();
129 } else if (batch->gen >= 4) {
130 BEGIN_BATCH(4, 1);
131 OUT_BATCH(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_WC_FLUSH |
132 PIPE_CONTROL_TC_FLUSH |
133 PIPE_CONTROL_WRITE_IMMEDIATE | 2);
134 OUT_RELOC(target_bo,
135 I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
136 PIPE_CONTROL_GLOBAL_GTT);
137 OUT_BATCH(val);
138 OUT_BATCH(0xdeadbeef);
139 ADVANCE_BATCH();
140 }
141
142 intel_batchbuffer_flush_on_ring(batch, 0);
143
144 drm_intel_bo_map(target_bo, 1);
145
146 buf = target_bo->virtual;
147 igt_assert(buf[0] == val);
148
149 drm_intel_bo_unmap(target_bo);
150 /* Make doublesure that this buffer won't get reused. */
151 drm_intel_bo_disable_reuse(target_bo);
152 drm_intel_bo_unreference(target_bo);
153
154 val++;
155 }
156 }
157
158 int fd;
159
160 igt_main
161 {
162 igt_fixture {
163 fd = drm_open_driver(DRIVER_INTEL);
164 igt_require_gem(fd);
165
166 devid = intel_get_drm_devid(fd);
167
168 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
169 igt_assert(bufmgr);
170
171 igt_skip_on(IS_GEN2(devid) || IS_GEN3(devid));
172 igt_skip_on(devid == PCI_CHIP_I965_G); /* has totally broken pipe control */
173
174 /* IMPORTANT: No call to
175 * drm_intel_bufmgr_gem_enable_reuse(bufmgr);
176 * here because we wan't to have fresh buffers (to trash the tlb)
177 * every time! */
178
179 batch = intel_batchbuffer_alloc(bufmgr, devid);
180 igt_assert(batch);
181 }
182
183 igt_subtest("fresh-buffer")
184 store_pipe_control_loop(false);
185
186 igt_subtest("reused-buffer")
187 store_pipe_control_loop(true);
188
189 igt_fixture {
190 intel_batchbuffer_free(batch);
191 drm_intel_bufmgr_destroy(bufmgr);
192
193 close(fd);
194 }
195 }
196