xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_create.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2015 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  *    Ankitprasad Sharma <ankitprasad.r.sharma at intel.com>
25  *
26  */
27 
28 /** @file gem_create.c
29  *
30  * This is a test for the extended and old gem_create ioctl, that
31  * includes allocation of object from stolen memory and shmem.
32  *
33  * The goal is to simply ensure that basics work and invalid input
34  * combinations are rejected.
35  */
36 
37 #include <stdlib.h>
38 #include <sys/ioctl.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <inttypes.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include <getopt.h>
47 #include <pthread.h>
48 #include <stdatomic.h>
49 
50 #include <drm.h>
51 
52 #include "ioctl_wrappers.h"
53 #include "intel_bufmgr.h"
54 #include "intel_batchbuffer.h"
55 #include "intel_io.h"
56 #include "intel_chipset.h"
57 #include "igt_aux.h"
58 #include "drmtest.h"
59 #include "drm.h"
60 #include "i915_drm.h"
61 
62 IGT_TEST_DESCRIPTION("This is a test for the extended & old gem_create ioctl,"
63 		     " that includes allocation of object from stolen memory"
64 		     " and shmem.");
65 
66 #define CLEAR(s) memset(&s, 0, sizeof(s))
67 #define PAGE_SIZE 4096
68 
69 struct local_i915_gem_create_v2 {
70 	uint64_t size;
71 	uint32_t handle;
72 	uint32_t pad;
73 #define I915_CREATE_PLACEMENT_STOLEN (1<<0)
74 	uint32_t flags;
75 } create_v2;
76 
77 #define LOCAL_IOCTL_I915_GEM_CREATE       DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct local_i915_gem_create_v2)
78 
invalid_flag_test(int fd)79 static void invalid_flag_test(int fd)
80 {
81 	int ret;
82 
83 	gem_require_stolen_support(fd);
84 
85 	create_v2.handle = 0;
86 	create_v2.size = PAGE_SIZE;
87 	create_v2.flags = ~I915_CREATE_PLACEMENT_STOLEN;
88 	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CREATE, &create_v2);
89 
90 	igt_assert(ret <= 0);
91 
92 	create_v2.flags = ~0;
93 	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CREATE, &create_v2);
94 
95 	igt_assert(ret <= 0);
96 }
97 
create_ioctl(int fd,struct drm_i915_gem_create * create)98 static int create_ioctl(int fd, struct drm_i915_gem_create *create)
99 {
100         int err = 0;
101 
102         if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, create)) {
103                 err = -errno;
104                 igt_assume(err != 0);
105         }
106 
107         errno = 0;
108         return err;
109 }
110 
invalid_size_test(int fd)111 static void invalid_size_test(int fd)
112 {
113 	struct drm_i915_gem_create create = {
114 		.size = 0,
115 	};
116 
117 	igt_assert_eq(create_ioctl(fd, &create), -EINVAL);
118 }
119 
120 /*
121  * Creating an object with non-aligned size and trying to access it with an
122  * offset, which is greater than the requested size but smaller than the
123  * object's last page boundary. pwrite here must be successful.
124  */
valid_nonaligned_size(int fd)125 static void valid_nonaligned_size(int fd)
126 {
127 	struct drm_i915_gem_create create = {
128 		.size = PAGE_SIZE / 2,
129 	};
130 	char buf[PAGE_SIZE];
131 
132 	igt_assert_eq(create_ioctl(fd, &create), 0);
133 
134 	gem_write(fd, create.handle, PAGE_SIZE / 2, buf, PAGE_SIZE / 2);
135 
136 	gem_close(fd, create.handle);
137 }
138 
139 /*
140  * Creating an object with non-aligned size and trying to access it with an
141  * offset, which is greater than the requested size and larger than the
142  * object's last page boundary. pwrite here must fail.
143  */
invalid_nonaligned_size(int fd)144 static void invalid_nonaligned_size(int fd)
145 {
146 	struct drm_i915_gem_create create = {
147 		.size = PAGE_SIZE / 2,
148 	};
149 	char buf[PAGE_SIZE];
150 
151 	igt_assert_eq(create_ioctl(fd, &create), 0);
152 
153 	/* This should fail. Hence cannot use gem_write. */
154 	igt_assert(__gem_write(fd, create.handle,
155 			       PAGE_SIZE / 2, buf, PAGE_SIZE));
156 
157 	gem_close(fd, create.handle);
158 }
159 
atomic_compare_swap_u64(_Atomic (uint64_t)* ptr,uint64_t oldval,uint64_t newval)160 static uint64_t atomic_compare_swap_u64(_Atomic(uint64_t) *ptr,
161 					uint64_t oldval, uint64_t newval)
162 {
163 	atomic_compare_exchange_strong(ptr, &oldval, newval);
164 	return oldval;
165 }
166 
get_npages(_Atomic (uint64_t)* global,uint64_t npages)167 static uint64_t get_npages(_Atomic(uint64_t) *global, uint64_t npages)
168 {
169 	uint64_t try, old, max;
170 
171 	max = *global;
172 	do {
173 		old = max;
174 		try = 1 + npages % (max / 2);
175 		max -= try;
176 	} while ((max = atomic_compare_swap_u64(global, old, max)) != old);
177 
178 	return try;
179 }
180 
181 struct thread_clear {
182 	_Atomic(uint64_t) max;
183 	int timeout;
184 	int i915;
185 };
186 
thread_clear(void * data)187 static void *thread_clear(void *data)
188 {
189 	struct thread_clear *arg = data;
190 	unsigned long checked = 0;
191 	int i915 = arg->i915;
192 
193 	igt_until_timeout(arg->timeout) {
194 		struct drm_i915_gem_create create = {};
195 		uint64_t npages;
196 
197 		npages = random();
198 		npages <<= 32;
199 		npages |= random();
200 		npages = get_npages(&arg->max, npages);
201 		create.size = npages << 12;
202 
203 		create_ioctl(i915, &create);
204 		for (uint64_t page = 0; page < npages; page++) {
205 			uint64_t x;
206 
207 			gem_read(i915, create.handle,
208 				 page * 4096 + (page % (4096 - sizeof(x))),
209 				 &x, sizeof(x));
210 			igt_assert_eq_u64(x, 0);
211 		}
212 		gem_close(i915, create.handle);
213 		checked += npages;
214 
215 		atomic_fetch_add(&arg->max, npages);
216 	}
217 
218 	return (void *)(uintptr_t)checked;
219 }
220 
always_clear(int i915,int timeout)221 static void always_clear(int i915, int timeout)
222 {
223 	struct thread_clear arg = {
224 		.i915 = i915,
225 		.timeout = timeout,
226 		.max = intel_get_avail_ram_mb() << (20 - 12), /* in pages */
227 	};
228 	const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
229 	unsigned long checked;
230 	pthread_t thread[ncpus];
231 	void *result;
232 
233 	for (int i = 0; i < ncpus; i++)
234 		pthread_create(&thread[i], NULL, thread_clear, &arg);
235 
236 	checked = 0;
237 	for (int i = 0; i < ncpus; i++) {
238 		pthread_join(thread[i], &result);
239 		checked += (uintptr_t)result;
240 	}
241 	igt_info("Checked %'lu page allocations\n", checked);
242 }
243 
size_update(int fd)244 static void size_update(int fd)
245 {
246 	int size_initial_nonaligned = 15;
247 
248 	struct drm_i915_gem_create create = {
249 		.size = size_initial_nonaligned,
250 	};
251 
252 	igt_assert_eq(create_ioctl(fd, &create), 0);
253 	igt_assert_neq(create.size, size_initial_nonaligned);
254 }
255 
256 igt_main
257 {
258 	int fd = -1;
259 
260 	igt_skip_on_simulation();
261 
262 	igt_fixture {
263 		fd = drm_open_driver(DRIVER_INTEL);
264 	}
265 
266 	igt_subtest("stolen-invalid-flag")
267 		invalid_flag_test(fd);
268 
269 	igt_subtest("create-invalid-size")
270 		invalid_size_test(fd);
271 
272 	igt_subtest("create-valid-nonaligned")
273 		valid_nonaligned_size(fd);
274 
275 	igt_subtest("create-invalid-nonaligned")
276 		invalid_nonaligned_size(fd);
277 
278 	igt_subtest("create-size-update")
279 		size_update(fd);
280 
281 	igt_subtest("create-clear")
282 		always_clear(fd, 30);
283 }
284