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 = >t_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