Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : *
4 : : * Copyright © 2014-2016 Intel Corporation
5 : : */
6 : :
7 : : #include <linux/anon_inodes.h>
8 : : #include <linux/mman.h>
9 : : #include <linux/pfn_t.h>
10 : : #include <linux/sizes.h>
11 : :
12 : : #include "gt/intel_gt.h"
13 : : #include "gt/intel_gt_requests.h"
14 : :
15 : : #include "i915_drv.h"
16 : : #include "i915_gem_gtt.h"
17 : : #include "i915_gem_ioctls.h"
18 : : #include "i915_gem_object.h"
19 : : #include "i915_gem_mman.h"
20 : : #include "i915_trace.h"
21 : : #include "i915_user_extensions.h"
22 : : #include "i915_vma.h"
23 : :
24 : : static inline bool
25 : 0 : __vma_matches(struct vm_area_struct *vma, struct file *filp,
26 : : unsigned long addr, unsigned long size)
27 : : {
28 : 0 : if (vma->vm_file != filp)
29 : : return false;
30 : :
31 [ # # ]: 0 : return vma->vm_start == addr &&
32 [ # # ]: 0 : (vma->vm_end - vma->vm_start) == PAGE_ALIGN(size);
33 : : }
34 : :
35 : : /**
36 : : * i915_gem_mmap_ioctl - Maps the contents of an object, returning the address
37 : : * it is mapped to.
38 : : * @dev: drm device
39 : : * @data: ioctl data blob
40 : : * @file: drm file
41 : : *
42 : : * While the mapping holds a reference on the contents of the object, it doesn't
43 : : * imply a ref on the object itself.
44 : : *
45 : : * IMPORTANT:
46 : : *
47 : : * DRM driver writers who look a this function as an example for how to do GEM
48 : : * mmap support, please don't implement mmap support like here. The modern way
49 : : * to implement DRM mmap support is with an mmap offset ioctl (like
50 : : * i915_gem_mmap_gtt) and then using the mmap syscall on the DRM fd directly.
51 : : * That way debug tooling like valgrind will understand what's going on, hiding
52 : : * the mmap call in a driver private ioctl will break that. The i915 driver only
53 : : * does cpu mmaps this way because we didn't know better.
54 : : */
55 : : int
56 : 0 : i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
57 : : struct drm_file *file)
58 : : {
59 : 0 : struct drm_i915_gem_mmap *args = data;
60 : 0 : struct drm_i915_gem_object *obj;
61 : 0 : unsigned long addr;
62 : :
63 [ # # ]: 0 : if (args->flags & ~(I915_MMAP_WC))
64 : : return -EINVAL;
65 : :
66 [ # # # # ]: 0 : if (args->flags & I915_MMAP_WC && !boot_cpu_has(X86_FEATURE_PAT))
67 : : return -ENODEV;
68 : :
69 : 0 : obj = i915_gem_object_lookup(file, args->handle);
70 [ # # ]: 0 : if (!obj)
71 : : return -ENOENT;
72 : :
73 : : /* prime objects have no backing filp to GEM mmap
74 : : * pages from.
75 : : */
76 [ # # ]: 0 : if (!obj->base.filp) {
77 : 0 : addr = -ENXIO;
78 : 0 : goto err;
79 : : }
80 : :
81 [ # # # # ]: 0 : if (range_overflows(args->offset, args->size, (u64)obj->base.size)) {
82 : 0 : addr = -EINVAL;
83 : 0 : goto err;
84 : : }
85 : :
86 : 0 : addr = vm_mmap(obj->base.filp, 0, args->size,
87 : : PROT_READ | PROT_WRITE, MAP_SHARED,
88 : : args->offset);
89 [ # # ]: 0 : if (IS_ERR_VALUE(addr))
90 : 0 : goto err;
91 : :
92 [ # # ]: 0 : if (args->flags & I915_MMAP_WC) {
93 : 0 : struct mm_struct *mm = current->mm;
94 : 0 : struct vm_area_struct *vma;
95 : :
96 [ # # ]: 0 : if (down_write_killable(&mm->mmap_sem)) {
97 : 0 : addr = -EINTR;
98 : 0 : goto err;
99 : : }
100 : 0 : vma = find_vma(mm, addr);
101 [ # # # # : 0 : if (vma && __vma_matches(vma, obj->base.filp, addr, args->size))
# # ]
102 : 0 : vma->vm_page_prot =
103 : 0 : pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
104 : : else
105 : : addr = -ENOMEM;
106 : 0 : up_write(&mm->mmap_sem);
107 [ # # ]: 0 : if (IS_ERR_VALUE(addr))
108 : 0 : goto err;
109 : : }
110 : 0 : i915_gem_object_put(obj);
111 : :
112 : 0 : args->addr_ptr = (u64)addr;
113 : 0 : return 0;
114 : :
115 : 0 : err:
116 : 0 : i915_gem_object_put(obj);
117 : 0 : return addr;
118 : : }
119 : :
120 : 0 : static unsigned int tile_row_pages(const struct drm_i915_gem_object *obj)
121 : : {
122 : 0 : return i915_gem_object_get_tile_row_size(obj) >> PAGE_SHIFT;
123 : : }
124 : :
125 : : /**
126 : : * i915_gem_mmap_gtt_version - report the current feature set for GTT mmaps
127 : : *
128 : : * A history of the GTT mmap interface:
129 : : *
130 : : * 0 - Everything had to fit into the GTT. Both parties of a memcpy had to
131 : : * aligned and suitable for fencing, and still fit into the available
132 : : * mappable space left by the pinned display objects. A classic problem
133 : : * we called the page-fault-of-doom where we would ping-pong between
134 : : * two objects that could not fit inside the GTT and so the memcpy
135 : : * would page one object in at the expense of the other between every
136 : : * single byte.
137 : : *
138 : : * 1 - Objects can be any size, and have any compatible fencing (X Y, or none
139 : : * as set via i915_gem_set_tiling() [DRM_I915_GEM_SET_TILING]). If the
140 : : * object is too large for the available space (or simply too large
141 : : * for the mappable aperture!), a view is created instead and faulted
142 : : * into userspace. (This view is aligned and sized appropriately for
143 : : * fenced access.)
144 : : *
145 : : * 2 - Recognise WC as a separate cache domain so that we can flush the
146 : : * delayed writes via GTT before performing direct access via WC.
147 : : *
148 : : * 3 - Remove implicit set-domain(GTT) and synchronisation on initial
149 : : * pagefault; swapin remains transparent.
150 : : *
151 : : * 4 - Support multiple fault handlers per object depending on object's
152 : : * backing storage (a.k.a. MMAP_OFFSET).
153 : : *
154 : : * Restrictions:
155 : : *
156 : : * * snoopable objects cannot be accessed via the GTT. It can cause machine
157 : : * hangs on some architectures, corruption on others. An attempt to service
158 : : * a GTT page fault from a snoopable object will generate a SIGBUS.
159 : : *
160 : : * * the object must be able to fit into RAM (physical memory, though no
161 : : * limited to the mappable aperture).
162 : : *
163 : : *
164 : : * Caveats:
165 : : *
166 : : * * a new GTT page fault will synchronize rendering from the GPU and flush
167 : : * all data to system memory. Subsequent access will not be synchronized.
168 : : *
169 : : * * all mappings are revoked on runtime device suspend.
170 : : *
171 : : * * there are only 8, 16 or 32 fence registers to share between all users
172 : : * (older machines require fence register for display and blitter access
173 : : * as well). Contention of the fence registers will cause the previous users
174 : : * to be unmapped and any new access will generate new page faults.
175 : : *
176 : : * * running out of memory while servicing a fault may generate a SIGBUS,
177 : : * rather than the expected SIGSEGV.
178 : : */
179 : 0 : int i915_gem_mmap_gtt_version(void)
180 : : {
181 : 0 : return 4;
182 : : }
183 : :
184 : : static inline struct i915_ggtt_view
185 : 0 : compute_partial_view(const struct drm_i915_gem_object *obj,
186 : : pgoff_t page_offset,
187 : : unsigned int chunk)
188 : : {
189 : 0 : struct i915_ggtt_view view;
190 : :
191 : 0 : if (i915_gem_object_is_tiled(obj))
192 [ # # ]: 0 : chunk = roundup(chunk, tile_row_pages(obj));
193 : :
194 : 0 : view.type = I915_GGTT_VIEW_PARTIAL;
195 : 0 : view.partial.offset = rounddown(page_offset, chunk);
196 : 0 : view.partial.size =
197 : 0 : min_t(unsigned int, chunk,
198 : : (obj->base.size >> PAGE_SHIFT) - view.partial.offset);
199 : :
200 : : /* If the partial covers the entire object, just create a normal VMA. */
201 [ # # ]: 0 : if (chunk >= obj->base.size >> PAGE_SHIFT)
202 : 0 : view.type = I915_GGTT_VIEW_NORMAL;
203 : :
204 : 0 : return view;
205 : : }
206 : :
207 : 0 : static vm_fault_t i915_error_to_vmf_fault(int err)
208 : : {
209 [ # # # # ]: 0 : switch (err) {
210 : 0 : default:
211 [ # # # # ]: 0 : WARN_ONCE(err, "unhandled error in %s: %i\n", __func__, err);
212 : : /* fallthrough */
213 : : case -EIO: /* shmemfs failure from swap device */
214 : : case -EFAULT: /* purged object */
215 : : case -ENODEV: /* bad object, how did you get here! */
216 : : case -ENXIO: /* unable to access backing store (on device) */
217 : : return VM_FAULT_SIGBUS;
218 : :
219 : : case -ENOSPC: /* shmemfs allocation failure */
220 : : case -ENOMEM: /* our allocation failure */
221 : : return VM_FAULT_OOM;
222 : :
223 : 0 : case 0:
224 : : case -EAGAIN:
225 : : case -ERESTARTSYS:
226 : : case -EINTR:
227 : : case -EBUSY:
228 : : /*
229 : : * EBUSY is ok: this just means that another thread
230 : : * already did the job.
231 : : */
232 : 0 : return VM_FAULT_NOPAGE;
233 : : }
234 : : }
235 : :
236 : 0 : static vm_fault_t vm_fault_cpu(struct vm_fault *vmf)
237 : : {
238 : 0 : struct vm_area_struct *area = vmf->vma;
239 : 0 : struct i915_mmap_offset *mmo = area->vm_private_data;
240 : 0 : struct drm_i915_gem_object *obj = mmo->obj;
241 : 0 : resource_size_t iomap;
242 : 0 : int err;
243 : :
244 : : /* Sanity check that we allow writing into this object */
245 [ # # # # ]: 0 : if (unlikely(i915_gem_object_is_readonly(obj) &&
246 : : area->vm_flags & VM_WRITE))
247 : : return VM_FAULT_SIGBUS;
248 : :
249 : 0 : err = i915_gem_object_pin_pages(obj);
250 [ # # ]: 0 : if (err)
251 : 0 : goto out;
252 : :
253 : 0 : iomap = -1;
254 [ # # ]: 0 : if (!i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_STRUCT_PAGE)) {
255 : 0 : iomap = obj->mm.region->iomap.base;
256 : 0 : iomap -= obj->mm.region->region.start;
257 : : }
258 : :
259 : : /* PTEs are revoked in obj->ops->put_pages() */
260 : 0 : err = remap_io_sg(area,
261 : 0 : area->vm_start, area->vm_end - area->vm_start,
262 : 0 : obj->mm.pages->sgl, iomap);
263 : :
264 [ # # ]: 0 : if (area->vm_flags & VM_WRITE) {
265 : 0 : GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
266 : 0 : obj->mm.dirty = true;
267 : : }
268 : :
269 : 0 : i915_gem_object_unpin_pages(obj);
270 : :
271 : 0 : out:
272 : 0 : return i915_error_to_vmf_fault(err);
273 : : }
274 : :
275 : 0 : static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
276 : : {
277 : : #define MIN_CHUNK_PAGES (SZ_1M >> PAGE_SHIFT)
278 : 0 : struct vm_area_struct *area = vmf->vma;
279 : 0 : struct i915_mmap_offset *mmo = area->vm_private_data;
280 : 0 : struct drm_i915_gem_object *obj = mmo->obj;
281 : 0 : struct drm_device *dev = obj->base.dev;
282 [ # # ]: 0 : struct drm_i915_private *i915 = to_i915(dev);
283 : 0 : struct intel_runtime_pm *rpm = &i915->runtime_pm;
284 : 0 : struct i915_ggtt *ggtt = &i915->ggtt;
285 : 0 : bool write = area->vm_flags & VM_WRITE;
286 : 0 : intel_wakeref_t wakeref;
287 : 0 : struct i915_vma *vma;
288 : 0 : pgoff_t page_offset;
289 : 0 : int srcu;
290 : 0 : int ret;
291 : :
292 : : /* Sanity check that we allow writing into this object */
293 [ # # # # ]: 0 : if (i915_gem_object_is_readonly(obj) && write)
294 : : return VM_FAULT_SIGBUS;
295 : :
296 : : /* We don't use vmf->pgoff since that has the fake offset */
297 : 0 : page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT;
298 : :
299 : 0 : trace_i915_gem_object_fault(obj, page_offset, true, write);
300 : :
301 : 0 : ret = i915_gem_object_pin_pages(obj);
302 [ # # ]: 0 : if (ret)
303 : 0 : goto err;
304 : :
305 : 0 : wakeref = intel_runtime_pm_get(rpm);
306 : :
307 : 0 : ret = intel_gt_reset_trylock(ggtt->vm.gt, &srcu);
308 [ # # ]: 0 : if (ret)
309 : 0 : goto err_rpm;
310 : :
311 : : /* Now pin it into the GTT as needed */
312 : 0 : vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
313 : : PIN_MAPPABLE |
314 : : PIN_NONBLOCK /* NOWARN */ |
315 : : PIN_NOEVICT);
316 [ # # ]: 0 : if (IS_ERR(vma)) {
317 : : /* Use a partial view if it is bigger than available space */
318 [ # # ]: 0 : struct i915_ggtt_view view =
319 : : compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
320 : 0 : unsigned int flags;
321 : :
322 : 0 : flags = PIN_MAPPABLE | PIN_NOSEARCH;
323 [ # # ]: 0 : if (view.type == I915_GGTT_VIEW_NORMAL)
324 : 0 : flags |= PIN_NONBLOCK; /* avoid warnings for pinned */
325 : :
326 : : /*
327 : : * Userspace is now writing through an untracked VMA, abandon
328 : : * all hope that the hardware is able to track future writes.
329 : : */
330 : :
331 : 0 : vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
332 [ # # ]: 0 : if (IS_ERR(vma)) {
333 : 0 : flags = PIN_MAPPABLE;
334 : 0 : view.type = I915_GGTT_VIEW_PARTIAL;
335 : 0 : vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
336 : : }
337 : :
338 : : /* The entire mappable GGTT is pinned? Unexpected! */
339 : 0 : GEM_BUG_ON(vma == ERR_PTR(-ENOSPC));
340 : : }
341 [ # # ]: 0 : if (IS_ERR(vma)) {
342 : 0 : ret = PTR_ERR(vma);
343 : 0 : goto err_reset;
344 : : }
345 : :
346 : : /* Access to snoopable pages through the GTT is incoherent. */
347 [ # # # # ]: 0 : if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(i915)) {
348 : 0 : ret = -EFAULT;
349 : 0 : goto err_unpin;
350 : : }
351 : :
352 : 0 : ret = i915_vma_pin_fence(vma);
353 [ # # ]: 0 : if (ret)
354 : 0 : goto err_unpin;
355 : :
356 : : /* Finally, remap it using the new GTT offset */
357 : 0 : ret = remap_io_mapping(area,
358 : 0 : area->vm_start + (vma->ggtt_view.partial.offset << PAGE_SHIFT),
359 : 0 : (ggtt->gmadr.start + vma->node.start) >> PAGE_SHIFT,
360 : 0 : min_t(u64, vma->size, area->vm_end - area->vm_start),
361 : : &ggtt->iomap);
362 [ # # ]: 0 : if (ret)
363 : 0 : goto err_fence;
364 : :
365 : 0 : assert_rpm_wakelock_held(rpm);
366 : :
367 : : /* Mark as being mmapped into userspace for later revocation */
368 : 0 : mutex_lock(&i915->ggtt.vm.mutex);
369 [ # # # # ]: 0 : if (!i915_vma_set_userfault(vma) && !obj->userfault_count++)
370 : 0 : list_add(&obj->userfault_link, &i915->ggtt.userfault_list);
371 : 0 : mutex_unlock(&i915->ggtt.vm.mutex);
372 : :
373 : : /* Track the mmo associated with the fenced vma */
374 : 0 : vma->mmo = mmo;
375 : :
376 : 0 : if (IS_ACTIVE(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND))
377 : 0 : intel_wakeref_auto(&i915->ggtt.userfault_wakeref,
378 : : msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND));
379 : :
380 [ # # ]: 0 : if (write) {
381 : 0 : GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
382 : 0 : i915_vma_set_ggtt_write(vma);
383 : 0 : obj->mm.dirty = true;
384 : : }
385 : :
386 : 0 : err_fence:
387 [ # # ]: 0 : i915_vma_unpin_fence(vma);
388 : 0 : err_unpin:
389 : 0 : __i915_vma_unpin(vma);
390 : 0 : err_reset:
391 : 0 : intel_gt_reset_unlock(ggtt->vm.gt, srcu);
392 : 0 : err_rpm:
393 : 0 : intel_runtime_pm_put(rpm, wakeref);
394 : 0 : i915_gem_object_unpin_pages(obj);
395 : 0 : err:
396 : 0 : return i915_error_to_vmf_fault(ret);
397 : : }
398 : :
399 : 0 : void __i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj)
400 : : {
401 : 0 : struct i915_vma *vma;
402 : :
403 : 0 : GEM_BUG_ON(!obj->userfault_count);
404 : :
405 [ # # # # ]: 0 : for_each_ggtt_vma(vma, obj)
406 : 0 : i915_vma_revoke_mmap(vma);
407 : :
408 : 0 : GEM_BUG_ON(obj->userfault_count);
409 : 0 : }
410 : :
411 : : /*
412 : : * It is vital that we remove the page mapping if we have mapped a tiled
413 : : * object through the GTT and then lose the fence register due to
414 : : * resource pressure. Similarly if the object has been moved out of the
415 : : * aperture, than pages mapped into userspace must be revoked. Removing the
416 : : * mapping will then trigger a page fault on the next user access, allowing
417 : : * fixup by vm_fault_gtt().
418 : : */
419 : 0 : static void i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj)
420 : : {
421 : 0 : struct drm_i915_private *i915 = to_i915(obj->base.dev);
422 : 0 : intel_wakeref_t wakeref;
423 : :
424 : : /*
425 : : * Serialisation between user GTT access and our code depends upon
426 : : * revoking the CPU's PTE whilst the mutex is held. The next user
427 : : * pagefault then has to wait until we release the mutex.
428 : : *
429 : : * Note that RPM complicates somewhat by adding an additional
430 : : * requirement that operations to the GGTT be made holding the RPM
431 : : * wakeref.
432 : : */
433 : 0 : wakeref = intel_runtime_pm_get(&i915->runtime_pm);
434 : 0 : mutex_lock(&i915->ggtt.vm.mutex);
435 : :
436 [ # # ]: 0 : if (!obj->userfault_count)
437 : 0 : goto out;
438 : :
439 : 0 : __i915_gem_object_release_mmap_gtt(obj);
440 : :
441 : : /*
442 : : * Ensure that the CPU's PTE are revoked and there are not outstanding
443 : : * memory transactions from userspace before we return. The TLB
444 : : * flushing implied above by changing the PTE above *should* be
445 : : * sufficient, an extra barrier here just provides us with a bit
446 : : * of paranoid documentation about our requirement to serialise
447 : : * memory writes before touching registers / GSM.
448 : : */
449 : 0 : wmb();
450 : :
451 : 0 : out:
452 : 0 : mutex_unlock(&i915->ggtt.vm.mutex);
453 : 0 : intel_runtime_pm_put(&i915->runtime_pm, wakeref);
454 : 0 : }
455 : :
456 : 0 : void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj)
457 : : {
458 : 0 : struct i915_mmap_offset *mmo, *mn;
459 : :
460 : 0 : spin_lock(&obj->mmo.lock);
461 [ # # # # : 0 : rbtree_postorder_for_each_entry_safe(mmo, mn,
# # ]
462 : : &obj->mmo.offsets, offset) {
463 : : /*
464 : : * vma_node_unmap for GTT mmaps handled already in
465 : : * __i915_gem_object_release_mmap_gtt
466 : : */
467 [ # # ]: 0 : if (mmo->mmap_type == I915_MMAP_TYPE_GTT)
468 : 0 : continue;
469 : :
470 : 0 : spin_unlock(&obj->mmo.lock);
471 : 0 : drm_vma_node_unmap(&mmo->vma_node,
472 : 0 : obj->base.dev->anon_inode->i_mapping);
473 : 0 : spin_lock(&obj->mmo.lock);
474 : : }
475 : 0 : spin_unlock(&obj->mmo.lock);
476 : 0 : }
477 : :
478 : : /**
479 : : * i915_gem_object_release_mmap - remove physical page mappings
480 : : * @obj: obj in question
481 : : *
482 : : * Preserve the reservation of the mmapping with the DRM core code, but
483 : : * relinquish ownership of the pages back to the system.
484 : : */
485 : 0 : void i915_gem_object_release_mmap(struct drm_i915_gem_object *obj)
486 : : {
487 : 0 : i915_gem_object_release_mmap_gtt(obj);
488 : 0 : i915_gem_object_release_mmap_offset(obj);
489 : 0 : }
490 : :
491 : : static struct i915_mmap_offset *
492 : 0 : lookup_mmo(struct drm_i915_gem_object *obj,
493 : : enum i915_mmap_type mmap_type)
494 : : {
495 : 0 : struct rb_node *rb;
496 : :
497 : 0 : spin_lock(&obj->mmo.lock);
498 : 0 : rb = obj->mmo.offsets.rb_node;
499 [ # # ]: 0 : while (rb) {
500 : 0 : struct i915_mmap_offset *mmo =
501 : 0 : rb_entry(rb, typeof(*mmo), offset);
502 : :
503 [ # # ]: 0 : if (mmo->mmap_type == mmap_type) {
504 : 0 : spin_unlock(&obj->mmo.lock);
505 : 0 : return mmo;
506 : : }
507 : :
508 [ # # ]: 0 : if (mmo->mmap_type < mmap_type)
509 : 0 : rb = rb->rb_right;
510 : : else
511 : 0 : rb = rb->rb_left;
512 : : }
513 : 0 : spin_unlock(&obj->mmo.lock);
514 : :
515 : 0 : return NULL;
516 : : }
517 : :
518 : : static struct i915_mmap_offset *
519 : 0 : insert_mmo(struct drm_i915_gem_object *obj, struct i915_mmap_offset *mmo)
520 : : {
521 : 0 : struct rb_node *rb, **p;
522 : :
523 : 0 : spin_lock(&obj->mmo.lock);
524 : 0 : rb = NULL;
525 : 0 : p = &obj->mmo.offsets.rb_node;
526 [ # # ]: 0 : while (*p) {
527 : 0 : struct i915_mmap_offset *pos;
528 : :
529 : 0 : rb = *p;
530 : 0 : pos = rb_entry(rb, typeof(*pos), offset);
531 : :
532 [ # # ]: 0 : if (pos->mmap_type == mmo->mmap_type) {
533 : 0 : spin_unlock(&obj->mmo.lock);
534 : 0 : drm_vma_offset_remove(obj->base.dev->vma_offset_manager,
535 : : &mmo->vma_node);
536 : 0 : kfree(mmo);
537 : 0 : return pos;
538 : : }
539 : :
540 [ # # ]: 0 : if (pos->mmap_type < mmo->mmap_type)
541 : 0 : p = &rb->rb_right;
542 : : else
543 : 0 : p = &rb->rb_left;
544 : : }
545 : 0 : rb_link_node(&mmo->offset, rb, p);
546 : 0 : rb_insert_color(&mmo->offset, &obj->mmo.offsets);
547 : 0 : spin_unlock(&obj->mmo.lock);
548 : :
549 : 0 : return mmo;
550 : : }
551 : :
552 : : static struct i915_mmap_offset *
553 : 0 : mmap_offset_attach(struct drm_i915_gem_object *obj,
554 : : enum i915_mmap_type mmap_type,
555 : : struct drm_file *file)
556 : : {
557 : 0 : struct drm_i915_private *i915 = to_i915(obj->base.dev);
558 : 0 : struct i915_mmap_offset *mmo;
559 : 0 : int err;
560 : :
561 : 0 : mmo = lookup_mmo(obj, mmap_type);
562 [ # # ]: 0 : if (mmo)
563 : 0 : goto out;
564 : :
565 : 0 : mmo = kmalloc(sizeof(*mmo), GFP_KERNEL);
566 [ # # ]: 0 : if (!mmo)
567 : : return ERR_PTR(-ENOMEM);
568 : :
569 : 0 : mmo->obj = obj;
570 : 0 : mmo->mmap_type = mmap_type;
571 : 0 : drm_vma_node_reset(&mmo->vma_node);
572 : :
573 : 0 : err = drm_vma_offset_add(obj->base.dev->vma_offset_manager,
574 : 0 : &mmo->vma_node, obj->base.size / PAGE_SIZE);
575 [ # # ]: 0 : if (likely(!err))
576 : 0 : goto insert;
577 : :
578 : : /* Attempt to reap some mmap space from dead objects */
579 : 0 : err = intel_gt_retire_requests_timeout(&i915->gt, MAX_SCHEDULE_TIMEOUT);
580 [ # # ]: 0 : if (err)
581 : 0 : goto err;
582 : :
583 : 0 : i915_gem_drain_freed_objects(i915);
584 : 0 : err = drm_vma_offset_add(obj->base.dev->vma_offset_manager,
585 : 0 : &mmo->vma_node, obj->base.size / PAGE_SIZE);
586 [ # # ]: 0 : if (err)
587 : 0 : goto err;
588 : :
589 : 0 : insert:
590 : 0 : mmo = insert_mmo(obj, mmo);
591 : 0 : GEM_BUG_ON(lookup_mmo(obj, mmap_type) != mmo);
592 : 0 : out:
593 [ # # ]: 0 : if (file)
594 : 0 : drm_vma_node_allow(&mmo->vma_node, file);
595 : : return mmo;
596 : :
597 : 0 : err:
598 : 0 : kfree(mmo);
599 : 0 : return ERR_PTR(err);
600 : : }
601 : :
602 : : static int
603 : 0 : __assign_mmap_offset(struct drm_file *file,
604 : : u32 handle,
605 : : enum i915_mmap_type mmap_type,
606 : : u64 *offset)
607 : : {
608 : 0 : struct drm_i915_gem_object *obj;
609 : 0 : struct i915_mmap_offset *mmo;
610 : 0 : int err;
611 : :
612 : 0 : obj = i915_gem_object_lookup(file, handle);
613 [ # # ]: 0 : if (!obj)
614 : : return -ENOENT;
615 : :
616 [ # # # # ]: 0 : if (mmap_type == I915_MMAP_TYPE_GTT &&
617 : : i915_gem_object_never_bind_ggtt(obj)) {
618 : 0 : err = -ENODEV;
619 : 0 : goto out;
620 : : }
621 : :
622 [ # # # # ]: 0 : if (mmap_type != I915_MMAP_TYPE_GTT &&
623 [ # # ]: 0 : !i915_gem_object_type_has(obj,
624 : : I915_GEM_OBJECT_HAS_STRUCT_PAGE |
625 : : I915_GEM_OBJECT_HAS_IOMEM)) {
626 : 0 : err = -ENODEV;
627 : 0 : goto out;
628 : : }
629 : :
630 : 0 : mmo = mmap_offset_attach(obj, mmap_type, file);
631 [ # # ]: 0 : if (IS_ERR(mmo)) {
632 : 0 : err = PTR_ERR(mmo);
633 : 0 : goto out;
634 : : }
635 : :
636 : 0 : *offset = drm_vma_node_offset_addr(&mmo->vma_node);
637 : 0 : err = 0;
638 : 0 : out:
639 : 0 : i915_gem_object_put(obj);
640 : 0 : return err;
641 : : }
642 : :
643 : : int
644 : 0 : i915_gem_dumb_mmap_offset(struct drm_file *file,
645 : : struct drm_device *dev,
646 : : u32 handle,
647 : : u64 *offset)
648 : : {
649 : 0 : enum i915_mmap_type mmap_type;
650 : :
651 [ # # ]: 0 : if (boot_cpu_has(X86_FEATURE_PAT))
652 : : mmap_type = I915_MMAP_TYPE_WC;
653 [ # # ]: 0 : else if (!i915_ggtt_has_aperture(&to_i915(dev)->ggtt))
654 : : return -ENODEV;
655 : : else
656 : : mmap_type = I915_MMAP_TYPE_GTT;
657 : :
658 : 0 : return __assign_mmap_offset(file, handle, mmap_type, offset);
659 : : }
660 : :
661 : : /**
662 : : * i915_gem_mmap_offset_ioctl - prepare an object for GTT mmap'ing
663 : : * @dev: DRM device
664 : : * @data: GTT mapping ioctl data
665 : : * @file: GEM object info
666 : : *
667 : : * Simply returns the fake offset to userspace so it can mmap it.
668 : : * The mmap call will end up in drm_gem_mmap(), which will set things
669 : : * up so we can get faults in the handler above.
670 : : *
671 : : * The fault handler will take care of binding the object into the GTT
672 : : * (since it may have been evicted to make room for something), allocating
673 : : * a fence register, and mapping the appropriate aperture address into
674 : : * userspace.
675 : : */
676 : : int
677 : 0 : i915_gem_mmap_offset_ioctl(struct drm_device *dev, void *data,
678 : : struct drm_file *file)
679 : : {
680 : 0 : struct drm_i915_private *i915 = to_i915(dev);
681 : 0 : struct drm_i915_gem_mmap_offset *args = data;
682 : 0 : enum i915_mmap_type type;
683 : 0 : int err;
684 : :
685 : : /*
686 : : * Historically we failed to check args.pad and args.offset
687 : : * and so we cannot use those fields for user input and we cannot
688 : : * add -EINVAL for them as the ABI is fixed, i.e. old userspace
689 : : * may be feeding in garbage in those fields.
690 : : *
691 : : * if (args->pad) return -EINVAL; is verbotten!
692 : : */
693 : :
694 : 0 : err = i915_user_extensions(u64_to_user_ptr(args->extensions),
695 : : NULL, 0, NULL);
696 [ # # ]: 0 : if (err)
697 : : return err;
698 : :
699 [ # # # # : 0 : switch (args->flags) {
# ]
700 : 0 : case I915_MMAP_OFFSET_GTT:
701 [ # # ]: 0 : if (!i915_ggtt_has_aperture(&i915->ggtt))
702 : : return -ENODEV;
703 : : type = I915_MMAP_TYPE_GTT;
704 : : break;
705 : :
706 : : case I915_MMAP_OFFSET_WC:
707 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_PAT))
708 : : return -ENODEV;
709 : : type = I915_MMAP_TYPE_WC;
710 : : break;
711 : :
712 : : case I915_MMAP_OFFSET_WB:
713 : : type = I915_MMAP_TYPE_WB;
714 : : break;
715 : :
716 : : case I915_MMAP_OFFSET_UC:
717 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_PAT))
718 : : return -ENODEV;
719 : : type = I915_MMAP_TYPE_UC;
720 : : break;
721 : :
722 : : default:
723 : : return -EINVAL;
724 : : }
725 : :
726 : 0 : return __assign_mmap_offset(file, args->handle, type, &args->offset);
727 : : }
728 : :
729 : 0 : static void vm_open(struct vm_area_struct *vma)
730 : : {
731 : 0 : struct i915_mmap_offset *mmo = vma->vm_private_data;
732 : 0 : struct drm_i915_gem_object *obj = mmo->obj;
733 : :
734 : 0 : GEM_BUG_ON(!obj);
735 : 0 : i915_gem_object_get(obj);
736 : 0 : }
737 : :
738 : 0 : static void vm_close(struct vm_area_struct *vma)
739 : : {
740 : 0 : struct i915_mmap_offset *mmo = vma->vm_private_data;
741 : 0 : struct drm_i915_gem_object *obj = mmo->obj;
742 : :
743 : 0 : GEM_BUG_ON(!obj);
744 : 0 : i915_gem_object_put(obj);
745 : 0 : }
746 : :
747 : : static const struct vm_operations_struct vm_ops_gtt = {
748 : : .fault = vm_fault_gtt,
749 : : .open = vm_open,
750 : : .close = vm_close,
751 : : };
752 : :
753 : : static const struct vm_operations_struct vm_ops_cpu = {
754 : : .fault = vm_fault_cpu,
755 : : .open = vm_open,
756 : : .close = vm_close,
757 : : };
758 : :
759 : 0 : static int singleton_release(struct inode *inode, struct file *file)
760 : : {
761 : 0 : struct drm_i915_private *i915 = file->private_data;
762 : :
763 : 0 : cmpxchg(&i915->gem.mmap_singleton, file, NULL);
764 : 0 : drm_dev_put(&i915->drm);
765 : :
766 : 0 : return 0;
767 : : }
768 : :
769 : : static const struct file_operations singleton_fops = {
770 : : .owner = THIS_MODULE,
771 : : .release = singleton_release,
772 : : };
773 : :
774 : 0 : static struct file *mmap_singleton(struct drm_i915_private *i915)
775 : : {
776 : 0 : struct file *file;
777 : :
778 : 0 : rcu_read_lock();
779 : 0 : file = i915->gem.mmap_singleton;
780 [ # # # # ]: 0 : if (file && !get_file_rcu(file))
781 : 0 : file = NULL;
782 : 0 : rcu_read_unlock();
783 [ # # ]: 0 : if (file)
784 : : return file;
785 : :
786 : 0 : file = anon_inode_getfile("i915.gem", &singleton_fops, i915, O_RDWR);
787 [ # # ]: 0 : if (IS_ERR(file))
788 : : return file;
789 : :
790 : : /* Everyone shares a single global address space */
791 : 0 : file->f_mapping = i915->drm.anon_inode->i_mapping;
792 : :
793 : 0 : smp_store_mb(i915->gem.mmap_singleton, file);
794 : 0 : drm_dev_get(&i915->drm);
795 : :
796 : 0 : return file;
797 : : }
798 : :
799 : : /*
800 : : * This overcomes the limitation in drm_gem_mmap's assignment of a
801 : : * drm_gem_object as the vma->vm_private_data. Since we need to
802 : : * be able to resolve multiple mmap offsets which could be tied
803 : : * to a single gem object.
804 : : */
805 : 0 : int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma)
806 : : {
807 : 0 : struct drm_vma_offset_node *node;
808 : 0 : struct drm_file *priv = filp->private_data;
809 : 0 : struct drm_device *dev = priv->minor->dev;
810 : 0 : struct drm_i915_gem_object *obj = NULL;
811 : 0 : struct i915_mmap_offset *mmo = NULL;
812 : 0 : struct file *anon;
813 : :
814 [ # # ]: 0 : if (drm_dev_is_unplugged(dev))
815 : : return -ENODEV;
816 : :
817 : 0 : rcu_read_lock();
818 : 0 : drm_vma_offset_lock_lookup(dev->vma_offset_manager);
819 : 0 : node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
820 : : vma->vm_pgoff,
821 : : vma_pages(vma));
822 [ # # ]: 0 : if (node && drm_vma_node_is_allowed(node, priv)) {
823 : : /*
824 : : * Skip 0-refcnted objects as it is in the process of being
825 : : * destroyed and will be invalid when the vma manager lock
826 : : * is released.
827 : : */
828 : 0 : mmo = container_of(node, struct i915_mmap_offset, vma_node);
829 [ # # ]: 0 : obj = i915_gem_object_get_rcu(mmo->obj);
830 : : }
831 : 0 : drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
832 : 0 : rcu_read_unlock();
833 [ # # ]: 0 : if (!obj)
834 [ # # ]: 0 : return node ? -EACCES : -EINVAL;
835 : :
836 [ # # ]: 0 : if (i915_gem_object_is_readonly(obj)) {
837 [ # # ]: 0 : if (vma->vm_flags & VM_WRITE) {
838 : 0 : i915_gem_object_put(obj);
839 : 0 : return -EINVAL;
840 : : }
841 : 0 : vma->vm_flags &= ~VM_MAYWRITE;
842 : : }
843 : :
844 : 0 : anon = mmap_singleton(to_i915(dev));
845 [ # # ]: 0 : if (IS_ERR(anon)) {
846 : 0 : i915_gem_object_put(obj);
847 : 0 : return PTR_ERR(anon);
848 : : }
849 : :
850 : 0 : vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
851 : 0 : vma->vm_private_data = mmo;
852 : :
853 : : /*
854 : : * We keep the ref on mmo->obj, not vm_file, but we require
855 : : * vma->vm_file->f_mapping, see vma_link(), for later revocation.
856 : : * Our userspace is accustomed to having per-file resource cleanup
857 : : * (i.e. contexts, objects and requests) on their close(fd), which
858 : : * requires avoiding extraneous references to their filp, hence why
859 : : * we prefer to use an anonymous file for their mmaps.
860 : : */
861 : 0 : fput(vma->vm_file);
862 : 0 : vma->vm_file = anon;
863 : :
864 [ # # # # : 0 : switch (mmo->mmap_type) {
# ]
865 : 0 : case I915_MMAP_TYPE_WC:
866 : 0 : vma->vm_page_prot =
867 : 0 : pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
868 : 0 : vma->vm_ops = &vm_ops_cpu;
869 : 0 : break;
870 : :
871 : 0 : case I915_MMAP_TYPE_WB:
872 : 0 : vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
873 : 0 : vma->vm_ops = &vm_ops_cpu;
874 : 0 : break;
875 : :
876 : 0 : case I915_MMAP_TYPE_UC:
877 : 0 : vma->vm_page_prot =
878 [ # # ]: 0 : pgprot_noncached(vm_get_page_prot(vma->vm_flags));
879 : 0 : vma->vm_ops = &vm_ops_cpu;
880 : 0 : break;
881 : :
882 : 0 : case I915_MMAP_TYPE_GTT:
883 : 0 : vma->vm_page_prot =
884 : 0 : pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
885 : 0 : vma->vm_ops = &vm_ops_gtt;
886 : 0 : break;
887 : : }
888 : 0 : vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
889 : :
890 : 0 : return 0;
891 : : }
892 : :
893 : : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
894 : : #include "selftests/i915_gem_mman.c"
895 : : #endif
|