1 /*
2  * Copyright © 2007, 2011, 2013, 2014, 2019 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 <stdbool.h>
26 #include <sys/ioctl.h>
27 #include <errno.h>
28 
29 #include "igt_core.h"
30 #include "ioctl_wrappers.h"
31 
32 #include "gem_mman.h"
33 
34 #ifdef HAVE_VALGRIND
35 #include <valgrind/valgrind.h>
36 #include <valgrind/memcheck.h>
37 
38 #define VG(x) x
39 #else
40 #define VG(x) do {} while (0)
41 #endif
42 
43 /**
44  * __gem_mmap__gtt:
45  * @fd: open i915 drm file descriptor
46  * @handle: gem buffer object handle
47  * @size: size of the gem buffer
48  * @prot: memory protection bits as used by mmap()
49  *
50  * This functions wraps up procedure to establish a memory mapping through the
51  * GTT.
52  *
53  * Returns: A pointer to the created memory mapping, NULL on failure.
54  */
__gem_mmap__gtt(int fd,uint32_t handle,uint64_t size,unsigned prot)55 void *__gem_mmap__gtt(int fd, uint32_t handle, uint64_t size, unsigned prot)
56 {
57 	struct drm_i915_gem_mmap_gtt mmap_arg;
58 	void *ptr;
59 
60 	memset(&mmap_arg, 0, sizeof(mmap_arg));
61 	mmap_arg.handle = handle;
62 	if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
63 		return NULL;
64 
65 	ptr = mmap64(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
66 	if (ptr == MAP_FAILED)
67 		ptr = NULL;
68 	else
69 		errno = 0;
70 
71 	VG(VALGRIND_MAKE_MEM_DEFINED(ptr, size));
72 
73 	return ptr;
74 }
75 
76 /**
77  * gem_mmap__gtt:
78  * @fd: open i915 drm file descriptor
79  * @handle: gem buffer object handle
80  * @size: size of the gem buffer
81  * @prot: memory protection bits as used by mmap()
82  *
83  * Like __gem_mmap__gtt() except we assert on failure.
84  *
85  * Returns: A pointer to the created memory mapping
86  */
gem_mmap__gtt(int fd,uint32_t handle,uint64_t size,unsigned prot)87 void *gem_mmap__gtt(int fd, uint32_t handle, uint64_t size, unsigned prot)
88 {
89 	void *ptr = __gem_mmap__gtt(fd, handle, size, prot);
90 	igt_assert(ptr);
91 	return ptr;
92 }
93 
gem_munmap(void * ptr,uint64_t size)94 int gem_munmap(void *ptr, uint64_t size)
95 {
96 	int ret = munmap(ptr, size);
97 
98 	if (ret == 0)
99 		VG(VALGRIND_MAKE_MEM_NOACCESS(ptr, size));
100 
101 	return ret;
102 }
103 
gem_mmap__has_wc(int fd)104 bool gem_mmap__has_wc(int fd)
105 {
106 	static int has_wc = -1;
107 
108 	if (has_wc == -1) {
109 		struct drm_i915_getparam gp;
110 		int mmap_version = -1;
111 		int gtt_version = -1;
112 
113 		has_wc = 0;
114 
115 		memset(&gp, 0, sizeof(gp));
116 		gp.param = I915_PARAM_MMAP_GTT_VERSION;
117 		gp.value = &gtt_version;
118 		ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
119 
120 		memset(&gp, 0, sizeof(gp));
121 		gp.param = I915_PARAM_MMAP_VERSION;
122 		gp.value = &mmap_version;
123 		ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
124 
125 		/* Do we have the new mmap_ioctl with DOMAIN_WC? */
126 		if (mmap_version >= 1 && gtt_version >= 2) {
127 			struct drm_i915_gem_mmap arg;
128 
129 			/* Does this device support wc-mmaps ? */
130 			memset(&arg, 0, sizeof(arg));
131 			arg.handle = gem_create(fd, 4096);
132 			arg.offset = 0;
133 			arg.size = 4096;
134 			arg.flags = I915_MMAP_WC;
135 			has_wc = igt_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg) == 0;
136 			gem_close(fd, arg.handle);
137 		}
138 		errno = 0;
139 	}
140 
141 	return has_wc > 0;
142 }
143 
144 /**
145  * __gem_mmap:
146  * @fd: open i915 drm file descriptor
147  * @handle: gem buffer object handle
148  * @offset: offset in the gem buffer of the mmap arena
149  * @size: size of the mmap arena
150  * @prot: memory protection bits as used by mmap()
151  * @flags: flags used to determine caching
152  *
153  * This functions wraps up procedure to establish a memory mapping through
154  * direct cpu access, bypassing the gpu (valid for wc == false). For wc == true
155  * it also bypass cpu caches completely and GTT system agent (i.e. there is no
156  * automatic tiling of the mmapping through the fence registers).
157  *
158  * Returns: A pointer to the created memory mapping, NULL on failure.
159  */
160 static void
__gem_mmap(int fd,uint32_t handle,uint64_t offset,uint64_t size,unsigned int prot,uint64_t flags)161 *__gem_mmap(int fd, uint32_t handle, uint64_t offset, uint64_t size, unsigned int prot, uint64_t flags)
162 {
163 	struct drm_i915_gem_mmap arg;
164 
165 	memset(&arg, 0, sizeof(arg));
166 	arg.handle = handle;
167 	arg.offset = offset;
168 	arg.size = size;
169 	arg.flags = flags;
170 
171 	if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg))
172 		return NULL;
173 
174 	VG(VALGRIND_MAKE_MEM_DEFINED(from_user_pointer(arg.addr_ptr), arg.size));
175 
176 	errno = 0;
177 	return from_user_pointer(arg.addr_ptr);
178 }
179 
180 /**
181  * __gem_mmap__wc:
182  * @fd: open i915 drm file descriptor
183  * @handle: gem buffer object handle
184  * @offset: offset in the gem buffer of the mmap arena
185  * @size: size of the mmap arena
186  * @prot: memory protection bits as used by mmap()
187  *
188  * This functions wraps up procedure to establish a memory mapping through
189  * direct cpu access, bypassing the gpu and cpu caches completely and also
190  * bypassing the GTT system agent (i.e. there is no automatic tiling of
191  * the mmapping through the fence registers).
192  *
193  * Returns: A pointer to the created memory mapping, NULL on failure.
194  */
__gem_mmap__wc(int fd,uint32_t handle,uint64_t offset,uint64_t size,unsigned prot)195 void *__gem_mmap__wc(int fd, uint32_t handle, uint64_t offset, uint64_t size, unsigned prot)
196 {
197 	return __gem_mmap(fd, handle, offset, size, prot, I915_MMAP_WC);
198 }
199 
200 /**
201  * gem_mmap__wc:
202  * @fd: open i915 drm file descriptor
203  * @handle: gem buffer object handle
204  * @offset: offset in the gem buffer of the mmap arena
205  * @size: size of the mmap arena
206  * @prot: memory protection bits as used by mmap()
207  *
208  * Like __gem_mmap__wc() except we assert on failure.
209  *
210  * Returns: A pointer to the created memory mapping
211  */
gem_mmap__wc(int fd,uint32_t handle,uint64_t offset,uint64_t size,unsigned prot)212 void *gem_mmap__wc(int fd, uint32_t handle, uint64_t offset, uint64_t size, unsigned prot)
213 {
214 	void *ptr = __gem_mmap__wc(fd, handle, offset, size, prot);
215 	igt_assert(ptr);
216 	return ptr;
217 }
218 
219 /**
220  * __gem_mmap__cpu:
221  * @fd: open i915 drm file descriptor
222  * @handle: gem buffer object handle
223  * @offset: offset in the gem buffer of the mmap arena
224  * @size: size of the mmap arena
225  * @prot: memory protection bits as used by mmap()
226  *
227  * This functions wraps up procedure to establish a memory mapping through
228  * direct cpu access, bypassing the gpu completely.
229  *
230  * Returns: A pointer to the created memory mapping, NULL on failure.
231  */
__gem_mmap__cpu(int fd,uint32_t handle,uint64_t offset,uint64_t size,unsigned prot)232 void *__gem_mmap__cpu(int fd, uint32_t handle, uint64_t offset, uint64_t size, unsigned prot)
233 {
234 	return __gem_mmap(fd, handle, offset, size, prot, 0);
235 }
236 
237 /**
238  * gem_mmap__cpu:
239  * @fd: open i915 drm file descriptor
240  * @handle: gem buffer object handle
241  * @offset: offset in the gem buffer of the mmap arena
242  * @size: size of the mmap arena
243  * @prot: memory protection bits as used by mmap()
244  *
245  * Like __gem_mmap__cpu() except we assert on failure.
246  *
247  * Returns: A pointer to the created memory mapping
248  */
gem_mmap__cpu(int fd,uint32_t handle,uint64_t offset,uint64_t size,unsigned prot)249 void *gem_mmap__cpu(int fd, uint32_t handle, uint64_t offset, uint64_t size, unsigned prot)
250 {
251 	void *ptr = __gem_mmap__cpu(fd, handle, offset, size, prot);
252 	igt_assert(ptr);
253 	return ptr;
254 }
255