blob: f705378173d76fc74e499ec81fc85e6be3eb80d9 [file] [log] [blame]
Chris Wilsone70c7892015-01-02 16:33:30 +05301/*
2 * Copyright © 2009 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/** @file gem_tiled_wc.c
25 *
26 * This is a test of write-combining mmap's behavior on tiled objects
27 * with respect to the reported swizzling value.
28 *
29 * The goal is to exercise the complications that arise when using a linear
30 * view of a tiled object that is subject to hardware swizzling. This is
31 * useful to check that we are presenting the correct view of the object
32 * to userspace, and that userspace has to respect the swizzle.
33 */
34
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 <sys/ioctl.h>
44#include "drm.h"
45#include "ioctl_wrappers.h"
46#include "drmtest.h"
47#include "intel_io.h"
48#include "intel_chipset.h"
49
50#define WIDTH 512
51#define HEIGHT 512
52#define SIZE (WIDTH*HEIGHT*sizeof(uint32_t))
53
54#define PAGE_SIZE 4096
55
56static int tile_width;
57static int tile_height;
58static int tile_size;
59
60static uint32_t
61create_bo(int fd)
62{
63 uint32_t handle;
64 uint32_t *data;
65 int i;
66
67 handle = gem_create(fd, SIZE);
68 gem_set_tiling(fd, handle, I915_TILING_X, WIDTH * sizeof(uint32_t));
69
70 /* Fill the BO with dwords starting at start_val */
Chris Wilson5e9fac52015-01-22 07:52:09 +000071 data = gem_mmap__gtt(fd, handle, SIZE, PROT_READ | PROT_WRITE);
Chris Wilsone70c7892015-01-02 16:33:30 +053072 for (i = 0; i < WIDTH*HEIGHT; i++)
73 data[i] = i;
74 munmap(data, SIZE);
75
76 return handle;
77}
78
79static int
80swizzle_bit(int bit, int offset)
81{
82 return (offset & (1 << bit)) >> (bit - 6);
83}
84
85/* Translate from a swizzled offset in the tiled buffer to the corresponding
86 * value from the original linear buffer.
87 */
88static uint32_t
89calculate_expected(int offset)
90{
91 int tile_off = offset & (tile_size - 1);
92 int tile_base = offset & -tile_size;
93 int tile_index = tile_base / tile_size;
94 int tiles_per_row = 4*WIDTH / tile_width;
95
96 /* base x,y values from the tile (page) index. */
97 int base_y = tile_index / tiles_per_row * tile_height;
98 int base_x = tile_index % tiles_per_row * (tile_width/4);
99
100 /* x, y offsets within the tile */
101 int tile_y = tile_off / tile_width;
102 int tile_x = (tile_off % tile_width) / 4;
103
Chris Wilson5e9fac52015-01-22 07:52:09 +0000104 igt_debug("%s(%d): %3d, %3d, %3d,%3d = %d\n",
105 __func__, offset, base_x, base_y, tile_x, tile_y,
106 (base_y + tile_y) * WIDTH + base_x + tile_x);
Chris Wilsone70c7892015-01-02 16:33:30 +0530107 return (base_y + tile_y) * WIDTH + base_x + tile_x;
108}
109
110static void
111get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle)
112{
113 struct drm_i915_gem_get_tiling2 {
114 uint32_t handle;
115 uint32_t tiling_mode;
116 uint32_t swizzle_mode;
117 uint32_t phys_swizzle_mode;
118 } arg;
119#define DRM_IOCTL_I915_GEM_GET_TILING2 DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling2)
120
121 memset(&arg, 0, sizeof(arg));
122 arg.handle = handle;
123
124 do_or_die(drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING2, &arg));
125 igt_require(arg.phys_swizzle_mode == arg.swizzle_mode);
126
127 *tiling = arg.tiling_mode;
128 *swizzle = arg.swizzle_mode;
129}
130
131igt_simple_main
132{
133 int fd;
134 int i, iter = 100;
135 uint32_t tiling, swizzle;
136 uint32_t handle;
137
138 fd = drm_open_any();
139 igt_require_mmap_wc(fd);
140
141 handle = create_bo(fd);
142 get_tiling(fd, handle, &tiling, &swizzle);
143
144 if (IS_GEN2(intel_get_drm_devid(fd))) {
145 tile_height = 16;
146 tile_width = 128;
147 tile_size = 2048;
148 } else {
149 tile_height = 8;
150 tile_width = 512;
151 tile_size = PAGE_SIZE;
152 }
153
154 /* Read a bunch of random subsets of the data and check that they come
155 * out right.
156 */
157 for (i = 0; i < iter; i++) {
158 int size = WIDTH * HEIGHT * 4;
159 int offset = (random() % size) & ~3;
160 int len = (random() % size) & ~3;
161 int first_page, last_page;
162 uint32_t *linear;
163 int j;
164
165 if (len == 0)
166 len = 4;
167
168 if (offset + len > size)
169 len = size - offset;
170
171 if (i == 0) {
172 offset = 0;
173 len = size;
174 }
175
176 first_page = offset & ~(PAGE_SIZE-1);
177 last_page = (offset + len + PAGE_SIZE) & ~(PAGE_SIZE-1);
Chris Wilsone70c7892015-01-02 16:33:30 +0530178
179 linear = gem_mmap__wc(fd, handle, first_page, last_page - first_page, PROT_READ);
180 igt_assert(linear);
181
182 /* Translate from offsets in the read buffer to the swizzled
183 * address that it corresponds to. This is the opposite of
184 * what Mesa does (calculate offset to be read given the linear
185 * offset it's looking for).
186 */
187 for (j = offset; j < offset + len; j += 4) {
188 uint32_t expected_val, found_val;
189 int swizzled_offset;
190 const char *swizzle_str;
191
192 switch (swizzle) {
193 case I915_BIT_6_SWIZZLE_NONE:
194 swizzled_offset = j;
195 swizzle_str = "none";
196 break;
197 case I915_BIT_6_SWIZZLE_9:
198 swizzled_offset = j ^
199 swizzle_bit(9, j);
200 swizzle_str = "bit9";
201 break;
202 case I915_BIT_6_SWIZZLE_9_10:
203 swizzled_offset = j ^
204 swizzle_bit(9, j) ^
205 swizzle_bit(10, j);
206 swizzle_str = "bit9^10";
207 break;
208 case I915_BIT_6_SWIZZLE_9_11:
209 swizzled_offset = j ^
210 swizzle_bit(9, j) ^
211 swizzle_bit(11, j);
212 swizzle_str = "bit9^11";
213 break;
214 case I915_BIT_6_SWIZZLE_9_10_11:
215 swizzled_offset = j ^
216 swizzle_bit(9, j) ^
217 swizzle_bit(10, j) ^
218 swizzle_bit(11, j);
219 swizzle_str = "bit9^10^11";
220 break;
221 default:
222 igt_skip("unknown swizzling");
223 break;
224 }
Chris Wilson5e9fac52015-01-22 07:52:09 +0000225 igt_debug("Checking offset %d swizzled %s -> %d\n",
226 j, swizzle_str, swizzled_offset);
Chris Wilsone70c7892015-01-02 16:33:30 +0530227 expected_val = calculate_expected(swizzled_offset);
Chris Wilson7848d212015-01-27 09:38:34 +0000228 found_val = linear[(j - first_page)/ 4];
Chris Wilsone70c7892015-01-02 16:33:30 +0530229 igt_assert_f(expected_val == found_val,
230 "Bad read [%d]: %d instead of %d at 0x%08x "
231 "for read from 0x%08x to 0x%08x, swizzle=%s\n",
232 i, found_val, expected_val, j,
233 offset, offset + len,
234 swizzle_str);
Chris Wilsone70c7892015-01-02 16:33:30 +0530235 }
Chris Wilson5e9fac52015-01-22 07:52:09 +0000236 munmap(linear, last_page - first_page);
Chris Wilsone70c7892015-01-02 16:33:30 +0530237 }
238
239 close(fd);
240}