1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2019 Intel Corporation
4 */
5
6 #include "i915_selftest.h"
7
8 #include "display/intel_display_core.h"
9 #include "gt/intel_context.h"
10 #include "gt/intel_engine_regs.h"
11 #include "gt/intel_engine_user.h"
12 #include "gt/intel_gpu_commands.h"
13 #include "gt/intel_gt.h"
14 #include "gt/intel_gt_regs.h"
15 #include "gem/i915_gem_lmem.h"
16
17 #include "gem/selftests/igt_gem_utils.h"
18 #include "selftests/igt_flush_test.h"
19 #include "selftests/mock_drm.h"
20 #include "selftests/i915_random.h"
21 #include "huge_gem_object.h"
22 #include "mock_context.h"
23
24 #define OW_SIZE 16 /* in bytes */
25 #define F_SUBTILE_SIZE 64 /* in bytes */
26 #define F_TILE_WIDTH 128 /* in bytes */
27 #define F_TILE_HEIGHT 32 /* in pixels */
28 #define F_SUBTILE_WIDTH OW_SIZE /* in bytes */
29 #define F_SUBTILE_HEIGHT 4 /* in pixels */
30
linear_x_y_to_ftiled_pos(int x,int y,u32 stride,int bpp)31 static int linear_x_y_to_ftiled_pos(int x, int y, u32 stride, int bpp)
32 {
33 int tile_base;
34 int tile_x, tile_y;
35 int swizzle, subtile;
36 int pixel_size = bpp / 8;
37 int pos;
38
39 /*
40 * Subtile remapping for F tile. Note that map[a]==b implies map[b]==a
41 * so we can use the same table to tile and until.
42 */
43 static const u8 f_subtile_map[] = {
44 0, 1, 2, 3, 8, 9, 10, 11,
45 4, 5, 6, 7, 12, 13, 14, 15,
46 16, 17, 18, 19, 24, 25, 26, 27,
47 20, 21, 22, 23, 28, 29, 30, 31,
48 32, 33, 34, 35, 40, 41, 42, 43,
49 36, 37, 38, 39, 44, 45, 46, 47,
50 48, 49, 50, 51, 56, 57, 58, 59,
51 52, 53, 54, 55, 60, 61, 62, 63
52 };
53
54 x *= pixel_size;
55 /*
56 * Where does the 4k tile start (in bytes)? This is the same for Y and
57 * F so we can use the Y-tile algorithm to get to that point.
58 */
59 tile_base =
60 y / F_TILE_HEIGHT * stride * F_TILE_HEIGHT +
61 x / F_TILE_WIDTH * 4096;
62
63 /* Find pixel within tile */
64 tile_x = x % F_TILE_WIDTH;
65 tile_y = y % F_TILE_HEIGHT;
66
67 /* And figure out the subtile within the 4k tile */
68 subtile = tile_y / F_SUBTILE_HEIGHT * 8 + tile_x / F_SUBTILE_WIDTH;
69
70 /* Swizzle the subtile number according to the bspec diagram */
71 swizzle = f_subtile_map[subtile];
72
73 /* Calculate new position */
74 pos = tile_base +
75 swizzle * F_SUBTILE_SIZE +
76 tile_y % F_SUBTILE_HEIGHT * OW_SIZE +
77 tile_x % F_SUBTILE_WIDTH;
78
79 GEM_BUG_ON(!IS_ALIGNED(pos, pixel_size));
80
81 return pos / pixel_size * 4;
82 }
83
84 enum client_tiling {
85 CLIENT_TILING_LINEAR,
86 CLIENT_TILING_X,
87 CLIENT_TILING_Y, /* Y-major, either Tile4 (Xe_HP and beyond) or legacy TileY */
88 CLIENT_NUM_TILING_TYPES
89 };
90
91 #define WIDTH 512
92 #define HEIGHT 32
93
94 struct blit_buffer {
95 struct i915_vma *vma;
96 u32 start_val;
97 enum client_tiling tiling;
98 };
99
100 struct tiled_blits {
101 struct intel_context *ce;
102 struct blit_buffer buffers[3];
103 struct blit_buffer scratch;
104 struct i915_vma *batch;
105 u64 hole;
106 u64 align;
107 u32 width;
108 u32 height;
109 };
110
fastblit_supports_x_tiling(const struct drm_i915_private * i915)111 static bool fastblit_supports_x_tiling(const struct drm_i915_private *i915)
112 {
113 int gen = GRAPHICS_VER(i915);
114
115 /* XY_FAST_COPY_BLT does not exist on pre-gen9 platforms */
116 drm_WARN_ON(&i915->drm, gen < 9);
117
118 if (gen < 12)
119 return true;
120
121 if (GRAPHICS_VER_FULL(i915) < IP_VER(12, 55))
122 return false;
123
124 return HAS_DISPLAY(i915);
125 }
126
fast_blit_ok(const struct blit_buffer * buf)127 static bool fast_blit_ok(const struct blit_buffer *buf)
128 {
129 /* XY_FAST_COPY_BLT does not exist on pre-gen9 platforms */
130 if (GRAPHICS_VER(buf->vma->vm->i915) < 9)
131 return false;
132
133 /* filter out platforms with unsupported X-tile support in fastblit */
134 if (buf->tiling == CLIENT_TILING_X && !fastblit_supports_x_tiling(buf->vma->vm->i915))
135 return false;
136
137 return true;
138 }
139
prepare_blit(const struct tiled_blits * t,struct blit_buffer * dst,struct blit_buffer * src,struct drm_i915_gem_object * batch)140 static int prepare_blit(const struct tiled_blits *t,
141 struct blit_buffer *dst,
142 struct blit_buffer *src,
143 struct drm_i915_gem_object *batch)
144 {
145 const int ver = GRAPHICS_VER(to_i915(batch->base.dev));
146 bool use_64b_reloc = ver >= 8;
147 u32 src_pitch, dst_pitch;
148 u32 cmd, *cs;
149
150 cs = i915_gem_object_pin_map_unlocked(batch, I915_MAP_WC);
151 if (IS_ERR(cs))
152 return PTR_ERR(cs);
153
154 if (fast_blit_ok(dst) && fast_blit_ok(src)) {
155 struct intel_gt *gt = t->ce->engine->gt;
156 u32 src_tiles = 0, dst_tiles = 0;
157 u32 src_4t = 0, dst_4t = 0;
158
159 /* Need to program BLIT_CCTL if it is not done previously
160 * before using XY_FAST_COPY_BLT
161 */
162 *cs++ = MI_LOAD_REGISTER_IMM(1);
163 *cs++ = i915_mmio_reg_offset(BLIT_CCTL(t->ce->engine->mmio_base));
164 *cs++ = (BLIT_CCTL_SRC_MOCS(gt->mocs.uc_index) |
165 BLIT_CCTL_DST_MOCS(gt->mocs.uc_index));
166
167 src_pitch = t->width; /* in dwords */
168 if (src->tiling == CLIENT_TILING_Y) {
169 src_tiles = XY_FAST_COPY_BLT_D0_SRC_TILE_MODE(YMAJOR);
170 if (GRAPHICS_VER_FULL(to_i915(batch->base.dev)) >= IP_VER(12, 55))
171 src_4t = XY_FAST_COPY_BLT_D1_SRC_TILE4;
172 } else if (src->tiling == CLIENT_TILING_X) {
173 src_tiles = XY_FAST_COPY_BLT_D0_SRC_TILE_MODE(TILE_X);
174 } else {
175 src_pitch *= 4; /* in bytes */
176 }
177
178 dst_pitch = t->width; /* in dwords */
179 if (dst->tiling == CLIENT_TILING_Y) {
180 dst_tiles = XY_FAST_COPY_BLT_D0_DST_TILE_MODE(YMAJOR);
181 if (GRAPHICS_VER_FULL(to_i915(batch->base.dev)) >= IP_VER(12, 55))
182 dst_4t = XY_FAST_COPY_BLT_D1_DST_TILE4;
183 } else if (dst->tiling == CLIENT_TILING_X) {
184 dst_tiles = XY_FAST_COPY_BLT_D0_DST_TILE_MODE(TILE_X);
185 } else {
186 dst_pitch *= 4; /* in bytes */
187 }
188
189 *cs++ = GEN9_XY_FAST_COPY_BLT_CMD | (10 - 2) |
190 src_tiles | dst_tiles;
191 *cs++ = src_4t | dst_4t | BLT_DEPTH_32 | dst_pitch;
192 *cs++ = 0;
193 *cs++ = t->height << 16 | t->width;
194 *cs++ = lower_32_bits(i915_vma_offset(dst->vma));
195 *cs++ = upper_32_bits(i915_vma_offset(dst->vma));
196 *cs++ = 0;
197 *cs++ = src_pitch;
198 *cs++ = lower_32_bits(i915_vma_offset(src->vma));
199 *cs++ = upper_32_bits(i915_vma_offset(src->vma));
200 } else {
201 if (ver >= 6) {
202 *cs++ = MI_LOAD_REGISTER_IMM(1);
203 *cs++ = i915_mmio_reg_offset(BCS_SWCTRL);
204 cmd = (BCS_SRC_Y | BCS_DST_Y) << 16;
205 if (src->tiling == CLIENT_TILING_Y)
206 cmd |= BCS_SRC_Y;
207 if (dst->tiling == CLIENT_TILING_Y)
208 cmd |= BCS_DST_Y;
209 *cs++ = cmd;
210
211 cmd = MI_FLUSH_DW;
212 if (ver >= 8)
213 cmd++;
214 *cs++ = cmd;
215 *cs++ = 0;
216 *cs++ = 0;
217 *cs++ = 0;
218 }
219
220 cmd = XY_SRC_COPY_BLT_CMD | BLT_WRITE_RGBA | (8 - 2);
221 if (ver >= 8)
222 cmd += 2;
223
224 src_pitch = t->width * 4;
225 if (src->tiling) {
226 cmd |= XY_SRC_COPY_BLT_SRC_TILED;
227 src_pitch /= 4;
228 }
229
230 dst_pitch = t->width * 4;
231 if (dst->tiling) {
232 cmd |= XY_SRC_COPY_BLT_DST_TILED;
233 dst_pitch /= 4;
234 }
235
236 *cs++ = cmd;
237 *cs++ = BLT_DEPTH_32 | BLT_ROP_SRC_COPY | dst_pitch;
238 *cs++ = 0;
239 *cs++ = t->height << 16 | t->width;
240 *cs++ = lower_32_bits(i915_vma_offset(dst->vma));
241 if (use_64b_reloc)
242 *cs++ = upper_32_bits(i915_vma_offset(dst->vma));
243 *cs++ = 0;
244 *cs++ = src_pitch;
245 *cs++ = lower_32_bits(i915_vma_offset(src->vma));
246 if (use_64b_reloc)
247 *cs++ = upper_32_bits(i915_vma_offset(src->vma));
248 }
249
250 *cs++ = MI_BATCH_BUFFER_END;
251
252 i915_gem_object_flush_map(batch);
253 i915_gem_object_unpin_map(batch);
254
255 return 0;
256 }
257
tiled_blits_destroy_buffers(struct tiled_blits * t)258 static void tiled_blits_destroy_buffers(struct tiled_blits *t)
259 {
260 int i;
261
262 for (i = 0; i < ARRAY_SIZE(t->buffers); i++)
263 i915_vma_put(t->buffers[i].vma);
264
265 i915_vma_put(t->scratch.vma);
266 i915_vma_put(t->batch);
267 }
268
269 static struct i915_vma *
__create_vma(struct tiled_blits * t,size_t size,bool lmem)270 __create_vma(struct tiled_blits *t, size_t size, bool lmem)
271 {
272 struct drm_i915_private *i915 = t->ce->vm->i915;
273 struct drm_i915_gem_object *obj;
274 struct i915_vma *vma;
275
276 if (lmem)
277 obj = i915_gem_object_create_lmem(i915, size, 0);
278 else
279 obj = i915_gem_object_create_shmem(i915, size);
280 if (IS_ERR(obj))
281 return ERR_CAST(obj);
282
283 vma = i915_vma_instance(obj, t->ce->vm, NULL);
284 if (IS_ERR(vma))
285 i915_gem_object_put(obj);
286
287 return vma;
288 }
289
create_vma(struct tiled_blits * t,bool lmem)290 static struct i915_vma *create_vma(struct tiled_blits *t, bool lmem)
291 {
292 return __create_vma(t, PAGE_ALIGN(t->width * t->height * 4), lmem);
293 }
294
tiled_blits_create_buffers(struct tiled_blits * t,int width,int height,struct rnd_state * prng)295 static int tiled_blits_create_buffers(struct tiled_blits *t,
296 int width, int height,
297 struct rnd_state *prng)
298 {
299 struct drm_i915_private *i915 = t->ce->engine->i915;
300 int i;
301
302 t->width = width;
303 t->height = height;
304
305 t->batch = __create_vma(t, PAGE_SIZE, false);
306 if (IS_ERR(t->batch))
307 return PTR_ERR(t->batch);
308
309 t->scratch.vma = create_vma(t, false);
310 if (IS_ERR(t->scratch.vma)) {
311 i915_vma_put(t->batch);
312 return PTR_ERR(t->scratch.vma);
313 }
314
315 for (i = 0; i < ARRAY_SIZE(t->buffers); i++) {
316 struct i915_vma *vma;
317
318 vma = create_vma(t, HAS_LMEM(i915) && i % 2);
319 if (IS_ERR(vma)) {
320 tiled_blits_destroy_buffers(t);
321 return PTR_ERR(vma);
322 }
323
324 t->buffers[i].vma = vma;
325 t->buffers[i].tiling =
326 i915_prandom_u32_max_state(CLIENT_NUM_TILING_TYPES, prng);
327 }
328
329 return 0;
330 }
331
fill_scratch(struct tiled_blits * t,u32 * vaddr,u32 val)332 static void fill_scratch(struct tiled_blits *t, u32 *vaddr, u32 val)
333 {
334 int i;
335
336 t->scratch.start_val = val;
337 for (i = 0; i < t->width * t->height; i++)
338 vaddr[i] = val++;
339
340 i915_gem_object_flush_map(t->scratch.vma->obj);
341 }
342
swizzle_bit(unsigned int bit,u64 offset)343 static u64 swizzle_bit(unsigned int bit, u64 offset)
344 {
345 return (offset & BIT_ULL(bit)) >> (bit - 6);
346 }
347
tiled_offset(const struct intel_gt * gt,u64 v,unsigned int stride,enum client_tiling tiling,int x_pos,int y_pos)348 static u64 tiled_offset(const struct intel_gt *gt,
349 u64 v,
350 unsigned int stride,
351 enum client_tiling tiling,
352 int x_pos, int y_pos)
353 {
354 unsigned int swizzle;
355 u64 x, y;
356
357 if (tiling == CLIENT_TILING_LINEAR)
358 return v;
359
360 y = div64_u64_rem(v, stride, &x);
361
362 if (tiling == CLIENT_TILING_X) {
363 v = div64_u64_rem(y, 8, &y) * stride * 8;
364 v += y * 512;
365 v += div64_u64_rem(x, 512, &x) << 12;
366 v += x;
367
368 swizzle = gt->ggtt->bit_6_swizzle_x;
369 } else if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 55)) {
370 /* Y-major tiling layout is Tile4 for Xe_HP and beyond */
371 v = linear_x_y_to_ftiled_pos(x_pos, y_pos, stride, 32);
372
373 /* no swizzling for f-tiling */
374 swizzle = I915_BIT_6_SWIZZLE_NONE;
375 } else {
376 const unsigned int ytile_span = 16;
377 const unsigned int ytile_height = 512;
378
379 v = div64_u64_rem(y, 32, &y) * stride * 32;
380 v += y * ytile_span;
381 v += div64_u64_rem(x, ytile_span, &x) * ytile_height;
382 v += x;
383
384 swizzle = gt->ggtt->bit_6_swizzle_y;
385 }
386
387 switch (swizzle) {
388 case I915_BIT_6_SWIZZLE_9:
389 v ^= swizzle_bit(9, v);
390 break;
391 case I915_BIT_6_SWIZZLE_9_10:
392 v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v);
393 break;
394 case I915_BIT_6_SWIZZLE_9_11:
395 v ^= swizzle_bit(9, v) ^ swizzle_bit(11, v);
396 break;
397 case I915_BIT_6_SWIZZLE_9_10_11:
398 v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v) ^ swizzle_bit(11, v);
399 break;
400 }
401
402 return v;
403 }
404
repr_tiling(enum client_tiling tiling)405 static const char *repr_tiling(enum client_tiling tiling)
406 {
407 switch (tiling) {
408 case CLIENT_TILING_LINEAR: return "linear";
409 case CLIENT_TILING_X: return "X";
410 case CLIENT_TILING_Y: return "Y / 4";
411 default: return "unknown";
412 }
413 }
414
verify_buffer(const struct tiled_blits * t,struct blit_buffer * buf,struct rnd_state * prng)415 static int verify_buffer(const struct tiled_blits *t,
416 struct blit_buffer *buf,
417 struct rnd_state *prng)
418 {
419 const u32 *vaddr;
420 int ret = 0;
421 int x, y, p;
422
423 x = i915_prandom_u32_max_state(t->width, prng);
424 y = i915_prandom_u32_max_state(t->height, prng);
425 p = y * t->width + x;
426
427 vaddr = i915_gem_object_pin_map_unlocked(buf->vma->obj, I915_MAP_WC);
428 if (IS_ERR(vaddr))
429 return PTR_ERR(vaddr);
430
431 if (vaddr[0] != buf->start_val) {
432 ret = -EINVAL;
433 } else {
434 u64 v = tiled_offset(buf->vma->vm->gt,
435 p * 4, t->width * 4,
436 buf->tiling, x, y);
437
438 if (vaddr[v / sizeof(*vaddr)] != buf->start_val + p)
439 ret = -EINVAL;
440 }
441 if (ret) {
442 pr_err("Invalid %s tiling detected at (%d, %d), start_val %x\n",
443 repr_tiling(buf->tiling),
444 x, y, buf->start_val);
445 igt_hexdump(vaddr, 4096);
446 }
447
448 i915_gem_object_unpin_map(buf->vma->obj);
449 return ret;
450 }
451
pin_buffer(struct i915_vma * vma,u64 addr)452 static int pin_buffer(struct i915_vma *vma, u64 addr)
453 {
454 int err;
455
456 if (drm_mm_node_allocated(&vma->node) && i915_vma_offset(vma) != addr) {
457 err = i915_vma_unbind_unlocked(vma);
458 if (err)
459 return err;
460 }
461
462 err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_OFFSET_FIXED | addr);
463 if (err)
464 return err;
465
466 GEM_BUG_ON(i915_vma_offset(vma) != addr);
467 return 0;
468 }
469
470 static int
tiled_blit(struct tiled_blits * t,struct blit_buffer * dst,u64 dst_addr,struct blit_buffer * src,u64 src_addr)471 tiled_blit(struct tiled_blits *t,
472 struct blit_buffer *dst, u64 dst_addr,
473 struct blit_buffer *src, u64 src_addr)
474 {
475 struct i915_request *rq;
476 int err;
477
478 err = pin_buffer(src->vma, src_addr);
479 if (err) {
480 pr_err("Cannot pin src @ %llx\n", src_addr);
481 return err;
482 }
483
484 err = pin_buffer(dst->vma, dst_addr);
485 if (err) {
486 pr_err("Cannot pin dst @ %llx\n", dst_addr);
487 goto err_src;
488 }
489
490 err = i915_vma_pin(t->batch, 0, 0, PIN_USER | PIN_HIGH);
491 if (err) {
492 pr_err("cannot pin batch\n");
493 goto err_dst;
494 }
495
496 err = prepare_blit(t, dst, src, t->batch->obj);
497 if (err)
498 goto err_bb;
499
500 rq = intel_context_create_request(t->ce);
501 if (IS_ERR(rq)) {
502 err = PTR_ERR(rq);
503 goto err_bb;
504 }
505
506 err = igt_vma_move_to_active_unlocked(t->batch, rq, 0);
507 if (!err)
508 err = igt_vma_move_to_active_unlocked(src->vma, rq, 0);
509 if (!err)
510 err = igt_vma_move_to_active_unlocked(dst->vma, rq, 0);
511 if (!err)
512 err = rq->engine->emit_bb_start(rq,
513 i915_vma_offset(t->batch),
514 i915_vma_size(t->batch),
515 0);
516 i915_request_get(rq);
517 i915_request_add(rq);
518 if (i915_request_wait(rq, 0, HZ / 2) < 0)
519 err = -ETIME;
520 i915_request_put(rq);
521
522 dst->start_val = src->start_val;
523 err_bb:
524 i915_vma_unpin(t->batch);
525 err_dst:
526 i915_vma_unpin(dst->vma);
527 err_src:
528 i915_vma_unpin(src->vma);
529 return err;
530 }
531
532 static struct tiled_blits *
tiled_blits_create(struct intel_engine_cs * engine,struct rnd_state * prng)533 tiled_blits_create(struct intel_engine_cs *engine, struct rnd_state *prng)
534 {
535 struct drm_mm_node hole;
536 struct tiled_blits *t;
537 u64 hole_size;
538 int err;
539
540 t = kzalloc(sizeof(*t), GFP_KERNEL);
541 if (!t)
542 return ERR_PTR(-ENOMEM);
543
544 t->ce = intel_context_create(engine);
545 if (IS_ERR(t->ce)) {
546 err = PTR_ERR(t->ce);
547 goto err_free;
548 }
549
550 t->align = i915_vm_min_alignment(t->ce->vm, INTEL_MEMORY_LOCAL);
551 t->align = max(t->align,
552 i915_vm_min_alignment(t->ce->vm, INTEL_MEMORY_SYSTEM));
553
554 hole_size = 2 * round_up(WIDTH * HEIGHT * 4, t->align);
555 hole_size *= 2; /* room to maneuver */
556 hole_size += 2 * t->align; /* padding on either side */
557
558 mutex_lock(&t->ce->vm->mutex);
559 memset(&hole, 0, sizeof(hole));
560 err = drm_mm_insert_node_in_range(&t->ce->vm->mm, &hole,
561 hole_size, t->align,
562 I915_COLOR_UNEVICTABLE,
563 0, U64_MAX,
564 DRM_MM_INSERT_BEST);
565 if (!err)
566 drm_mm_remove_node(&hole);
567 mutex_unlock(&t->ce->vm->mutex);
568 if (err) {
569 err = -ENODEV;
570 goto err_put;
571 }
572
573 t->hole = hole.start + t->align;
574 pr_info("Using hole at %llx\n", t->hole);
575
576 err = tiled_blits_create_buffers(t, WIDTH, HEIGHT, prng);
577 if (err)
578 goto err_put;
579
580 return t;
581
582 err_put:
583 intel_context_put(t->ce);
584 err_free:
585 kfree(t);
586 return ERR_PTR(err);
587 }
588
tiled_blits_destroy(struct tiled_blits * t)589 static void tiled_blits_destroy(struct tiled_blits *t)
590 {
591 tiled_blits_destroy_buffers(t);
592
593 intel_context_put(t->ce);
594 kfree(t);
595 }
596
tiled_blits_prepare(struct tiled_blits * t,struct rnd_state * prng)597 static int tiled_blits_prepare(struct tiled_blits *t,
598 struct rnd_state *prng)
599 {
600 u64 offset = round_up(t->width * t->height * 4, t->align);
601 u32 *map;
602 int err;
603 int i;
604
605 map = i915_gem_object_pin_map_unlocked(t->scratch.vma->obj, I915_MAP_WC);
606 if (IS_ERR(map))
607 return PTR_ERR(map);
608
609 /* Use scratch to fill objects */
610 for (i = 0; i < ARRAY_SIZE(t->buffers); i++) {
611 fill_scratch(t, map, prandom_u32_state(prng));
612 GEM_BUG_ON(verify_buffer(t, &t->scratch, prng));
613
614 err = tiled_blit(t,
615 &t->buffers[i], t->hole + offset,
616 &t->scratch, t->hole);
617 if (err == 0)
618 err = verify_buffer(t, &t->buffers[i], prng);
619 if (err) {
620 pr_err("Failed to create buffer %d\n", i);
621 break;
622 }
623 }
624
625 i915_gem_object_unpin_map(t->scratch.vma->obj);
626 return err;
627 }
628
tiled_blits_bounce(struct tiled_blits * t,struct rnd_state * prng)629 static int tiled_blits_bounce(struct tiled_blits *t, struct rnd_state *prng)
630 {
631 u64 offset = round_up(t->width * t->height * 4, 2 * t->align);
632 int err;
633
634 /* We want to check position invariant tiling across GTT eviction */
635
636 err = tiled_blit(t,
637 &t->buffers[1], t->hole + offset / 2,
638 &t->buffers[0], t->hole + 2 * offset);
639 if (err)
640 return err;
641
642 /* Simulating GTT eviction of the same buffer / layout */
643 t->buffers[2].tiling = t->buffers[0].tiling;
644
645 /* Reposition so that we overlap the old addresses, and slightly off */
646 err = tiled_blit(t,
647 &t->buffers[2], t->hole + t->align,
648 &t->buffers[1], t->hole + 3 * offset / 2);
649 if (err)
650 return err;
651
652 err = verify_buffer(t, &t->buffers[2], prng);
653 if (err)
654 return err;
655
656 return 0;
657 }
658
__igt_client_tiled_blits(struct intel_engine_cs * engine,struct rnd_state * prng)659 static int __igt_client_tiled_blits(struct intel_engine_cs *engine,
660 struct rnd_state *prng)
661 {
662 struct tiled_blits *t;
663 int err;
664
665 t = tiled_blits_create(engine, prng);
666 if (IS_ERR(t))
667 return PTR_ERR(t);
668
669 err = tiled_blits_prepare(t, prng);
670 if (err)
671 goto out;
672
673 err = tiled_blits_bounce(t, prng);
674 if (err)
675 goto out;
676
677 out:
678 tiled_blits_destroy(t);
679 return err;
680 }
681
has_bit17_swizzle(int sw)682 static bool has_bit17_swizzle(int sw)
683 {
684 return (sw == I915_BIT_6_SWIZZLE_9_10_17 ||
685 sw == I915_BIT_6_SWIZZLE_9_17);
686 }
687
bad_swizzling(struct drm_i915_private * i915)688 static bool bad_swizzling(struct drm_i915_private *i915)
689 {
690 struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
691
692 if (i915->gem_quirks & GEM_QUIRK_PIN_SWIZZLED_PAGES)
693 return true;
694
695 if (has_bit17_swizzle(ggtt->bit_6_swizzle_x) ||
696 has_bit17_swizzle(ggtt->bit_6_swizzle_y))
697 return true;
698
699 return false;
700 }
701
igt_client_tiled_blits(void * arg)702 static int igt_client_tiled_blits(void *arg)
703 {
704 struct drm_i915_private *i915 = arg;
705 I915_RND_STATE(prng);
706 int inst = 0;
707
708 /* Test requires explicit BLT tiling controls */
709 if (GRAPHICS_VER(i915) < 4)
710 return 0;
711
712 if (bad_swizzling(i915)) /* Requires sane (sub-page) swizzling */
713 return 0;
714
715 do {
716 struct intel_engine_cs *engine;
717 int err;
718
719 engine = intel_engine_lookup_user(i915,
720 I915_ENGINE_CLASS_COPY,
721 inst++);
722 if (!engine)
723 return 0;
724
725 err = __igt_client_tiled_blits(engine, &prng);
726 if (err == -ENODEV)
727 err = 0;
728 if (err)
729 return err;
730 } while (1);
731 }
732
i915_gem_client_blt_live_selftests(struct drm_i915_private * i915)733 int i915_gem_client_blt_live_selftests(struct drm_i915_private *i915)
734 {
735 static const struct i915_subtest tests[] = {
736 SUBTEST(igt_client_tiled_blits),
737 };
738
739 if (intel_gt_is_wedged(to_gt(i915)))
740 return 0;
741
742 return i915_live_subtests(tests, i915);
743 }
744