xref: /freebsd/sys/dev/drm2/ttm/ttm_bo_vm.c (revision 0d48d1ffe0446cd2f87ce02555e3d17772ae7284)
1 /**************************************************************************
2  *
3  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 /*
28  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
29  */
30 /*
31  * Copyright (c) 2013 The FreeBSD Foundation
32  * All rights reserved.
33  *
34  * Portions of this software were developed by Konstantin Belousov
35  * <kib@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
36  */
37 
38 #include <sys/cdefs.h>
39 #include "opt_vm.h"
40 
41 #include <dev/drm2/drmP.h>
42 #include <dev/drm2/ttm/ttm_module.h>
43 #include <dev/drm2/ttm/ttm_bo_driver.h>
44 #include <dev/drm2/ttm/ttm_placement.h>
45 
46 #include <vm/vm.h>
47 #include <vm/vm_page.h>
48 #include <vm/vm_pageout.h>
49 
50 #define TTM_BO_VM_NUM_PREFAULT 16
51 
52 RB_GENERATE(ttm_bo_device_buffer_objects, ttm_buffer_object, vm_rb,
53     ttm_bo_cmp_rb_tree_items);
54 
55 int
56 ttm_bo_cmp_rb_tree_items(struct ttm_buffer_object *a,
57     struct ttm_buffer_object *b)
58 {
59 
60 	if (a->vm_node->start < b->vm_node->start) {
61 		return (-1);
62 	} else if (a->vm_node->start > b->vm_node->start) {
63 		return (1);
64 	} else {
65 		return (0);
66 	}
67 }
68 
69 static struct ttm_buffer_object *ttm_bo_vm_lookup_rb(struct ttm_bo_device *bdev,
70 						     unsigned long page_start,
71 						     unsigned long num_pages)
72 {
73 	unsigned long cur_offset;
74 	struct ttm_buffer_object *bo;
75 	struct ttm_buffer_object *best_bo = NULL;
76 
77 	bo = RB_ROOT(&bdev->addr_space_rb);
78 	while (bo != NULL) {
79 		cur_offset = bo->vm_node->start;
80 		if (page_start >= cur_offset) {
81 			best_bo = bo;
82 			if (page_start == cur_offset)
83 				break;
84 			bo = RB_RIGHT(bo, vm_rb);
85 		} else
86 			bo = RB_LEFT(bo, vm_rb);
87 	}
88 
89 	if (unlikely(best_bo == NULL))
90 		return NULL;
91 
92 	if (unlikely((best_bo->vm_node->start + best_bo->num_pages) <
93 		     (page_start + num_pages)))
94 		return NULL;
95 
96 	return best_bo;
97 }
98 
99 static int
100 ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset,
101     int prot, vm_page_t *mres)
102 {
103 	struct pctrie_iter pages;
104 	struct ttm_buffer_object *bo = vm_obj->handle;
105 	struct ttm_bo_device *bdev = bo->bdev;
106 	struct ttm_tt *ttm = NULL;
107 	vm_page_t m, m1;
108 	int ret;
109 	int retval = VM_PAGER_OK;
110 	struct ttm_mem_type_manager *man =
111 		&bdev->man[bo->mem.mem_type];
112 
113 	vm_object_pip_add(vm_obj, 1);
114 	if (*mres != NULL) {
115 		(void)vm_page_remove(*mres);
116 	}
117 	vm_page_iter_init(&pages, vm_obj);
118 retry:
119 	VM_OBJECT_WUNLOCK(vm_obj);
120 	m = NULL;
121 
122 reserve:
123 	ret = ttm_bo_reserve(bo, false, false, false, 0);
124 	if (unlikely(ret != 0)) {
125 		if (ret == -EBUSY) {
126 			kern_yield(PRI_USER);
127 			goto reserve;
128 		}
129 	}
130 
131 	if (bdev->driver->fault_reserve_notify) {
132 		ret = bdev->driver->fault_reserve_notify(bo);
133 		switch (ret) {
134 		case 0:
135 			break;
136 		case -EBUSY:
137 		case -ERESTARTSYS:
138 		case -EINTR:
139 			kern_yield(PRI_USER);
140 			goto reserve;
141 		default:
142 			retval = VM_PAGER_ERROR;
143 			goto out_unlock;
144 		}
145 	}
146 
147 	/*
148 	 * Wait for buffer data in transit, due to a pipelined
149 	 * move.
150 	 */
151 
152 	mtx_lock(&bdev->fence_lock);
153 	if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) {
154 		/*
155 		 * Here, the behavior differs between Linux and FreeBSD.
156 		 *
157 		 * On Linux, the wait is interruptible (3rd argument to
158 		 * ttm_bo_wait). There must be some mechanism to resume
159 		 * page fault handling, once the signal is processed.
160 		 *
161 		 * On FreeBSD, the wait is uninteruptible. This is not a
162 		 * problem as we can't end up with an unkillable process
163 		 * here, because the wait will eventually time out.
164 		 *
165 		 * An example of this situation is the Xorg process
166 		 * which uses SIGALRM internally. The signal could
167 		 * interrupt the wait, causing the page fault to fail
168 		 * and the process to receive SIGSEGV.
169 		 */
170 		ret = ttm_bo_wait(bo, false, false, false);
171 		mtx_unlock(&bdev->fence_lock);
172 		if (unlikely(ret != 0)) {
173 			retval = VM_PAGER_ERROR;
174 			goto out_unlock;
175 		}
176 	} else
177 		mtx_unlock(&bdev->fence_lock);
178 
179 	ret = ttm_mem_io_lock(man, true);
180 	if (unlikely(ret != 0)) {
181 		retval = VM_PAGER_ERROR;
182 		goto out_unlock;
183 	}
184 	ret = ttm_mem_io_reserve_vm(bo);
185 	if (unlikely(ret != 0)) {
186 		retval = VM_PAGER_ERROR;
187 		goto out_io_unlock;
188 	}
189 
190 	/*
191 	 * Strictly, we're not allowed to modify vma->vm_page_prot here,
192 	 * since the mmap_sem is only held in read mode. However, we
193 	 * modify only the caching bits of vma->vm_page_prot and
194 	 * consider those bits protected by
195 	 * the bo->mutex, as we should be the only writers.
196 	 * There shouldn't really be any readers of these bits except
197 	 * within vm_insert_mixed()? fork?
198 	 *
199 	 * TODO: Add a list of vmas to the bo, and change the
200 	 * vma->vm_page_prot when the object changes caching policy, with
201 	 * the correct locks held.
202 	 */
203 	if (!bo->mem.bus.is_iomem) {
204 		/* Allocate all page at once, most common usage */
205 		ttm = bo->ttm;
206 		if (ttm->bdev->driver->ttm_tt_populate(ttm)) {
207 			retval = VM_PAGER_ERROR;
208 			goto out_io_unlock;
209 		}
210 	}
211 
212 	if (bo->mem.bus.is_iomem) {
213 		m = PHYS_TO_VM_PAGE(bo->mem.bus.base + bo->mem.bus.offset +
214 		    offset);
215 		KASSERT((m->flags & PG_FICTITIOUS) != 0,
216 		    ("physical address %#jx not fictitious",
217 		    (uintmax_t)(bo->mem.bus.base + bo->mem.bus.offset
218 		    + offset)));
219 		pmap_page_set_memattr(m, ttm_io_prot(bo->mem.placement));
220 	} else {
221 		ttm = bo->ttm;
222 		m = ttm->pages[OFF_TO_IDX(offset)];
223 		if (unlikely(!m)) {
224 			retval = VM_PAGER_ERROR;
225 			goto out_io_unlock;
226 		}
227 		pmap_page_set_memattr(m,
228 		    (bo->mem.placement & TTM_PL_FLAG_CACHED) ?
229 		    VM_MEMATTR_WRITE_BACK : ttm_io_prot(bo->mem.placement));
230 	}
231 
232 	VM_OBJECT_WLOCK(vm_obj);
233 	if (vm_page_busy_acquire(m, VM_ALLOC_WAITFAIL) == 0) {
234 		ttm_mem_io_unlock(man);
235 		ttm_bo_unreserve(bo);
236 		goto retry;
237 	}
238 	pctrie_iter_reset(&pages);
239 	m1 = vm_radix_iter_lookup(&pages, OFF_TO_IDX(offset));
240 	/* XXX This looks like it should just be vm_page_replace? */
241 	if (m1 == NULL) {
242 		if (vm_page_iter_insert(
243 		    m, vm_obj, OFF_TO_IDX(offset), &pages) != 0) {
244 			vm_page_xunbusy(m);
245 			VM_OBJECT_WUNLOCK(vm_obj);
246 			vm_wait(vm_obj);
247 			VM_OBJECT_WLOCK(vm_obj);
248 			ttm_mem_io_unlock(man);
249 			ttm_bo_unreserve(bo);
250 			goto retry;
251 		}
252 	} else {
253 		KASSERT(m == m1,
254 		    ("inconsistent insert bo %p m %p m1 %p offset %jx",
255 		    bo, m, m1, (uintmax_t)offset));
256 	}
257 	vm_page_valid(m);
258 	if (*mres != NULL) {
259 		KASSERT(*mres != m, ("losing %p %p", *mres, m));
260 		vm_page_xunbusy(*mres);
261 		vm_page_free(*mres);
262 	}
263 	*mres = m;
264 
265 out_io_unlock1:
266 	ttm_mem_io_unlock(man);
267 out_unlock1:
268 	ttm_bo_unreserve(bo);
269 	vm_object_pip_wakeup(vm_obj);
270 	return (retval);
271 
272 out_io_unlock:
273 	VM_OBJECT_WLOCK(vm_obj);
274 	goto out_io_unlock1;
275 
276 out_unlock:
277 	VM_OBJECT_WLOCK(vm_obj);
278 	goto out_unlock1;
279 }
280 
281 static int
282 ttm_bo_vm_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
283     vm_ooffset_t foff, struct ucred *cred, u_short *color)
284 {
285 
286 	/*
287 	 * On Linux, a reference to the buffer object is acquired here.
288 	 * The reason is that this function is not called when the
289 	 * mmap() is initialized, but only when a process forks for
290 	 * instance. Therefore on Linux, the reference on the bo is
291 	 * acquired either in ttm_bo_mmap() or ttm_bo_vm_open(). It's
292 	 * then released in ttm_bo_vm_close().
293 	 *
294 	 * Here, this function is called during mmap() initialization.
295 	 * Thus, the reference acquired in ttm_bo_mmap_single() is
296 	 * sufficient.
297 	 */
298 
299 	*color = 0;
300 	return (0);
301 }
302 
303 static void
304 ttm_bo_vm_dtor(void *handle)
305 {
306 	struct ttm_buffer_object *bo = handle;
307 
308 	ttm_bo_unref(&bo);
309 }
310 
311 static struct cdev_pager_ops ttm_pager_ops = {
312 	.cdev_pg_fault = ttm_bo_vm_fault,
313 	.cdev_pg_ctor = ttm_bo_vm_ctor,
314 	.cdev_pg_dtor = ttm_bo_vm_dtor
315 };
316 
317 int
318 ttm_bo_mmap_single(struct ttm_bo_device *bdev, vm_ooffset_t *offset, vm_size_t size,
319     struct vm_object **obj_res, int nprot)
320 {
321 	struct ttm_bo_driver *driver;
322 	struct ttm_buffer_object *bo;
323 	struct vm_object *vm_obj;
324 	int ret;
325 
326 	rw_wlock(&bdev->vm_lock);
327 	bo = ttm_bo_vm_lookup_rb(bdev, OFF_TO_IDX(*offset), OFF_TO_IDX(size));
328 	if (likely(bo != NULL))
329 		refcount_acquire(&bo->kref);
330 	rw_wunlock(&bdev->vm_lock);
331 
332 	if (unlikely(bo == NULL)) {
333 		printf("[TTM] Could not find buffer object to map\n");
334 		return (-EINVAL);
335 	}
336 
337 	driver = bo->bdev->driver;
338 	if (unlikely(!driver->verify_access)) {
339 		ret = -EPERM;
340 		goto out_unref;
341 	}
342 	ret = driver->verify_access(bo);
343 	if (unlikely(ret != 0))
344 		goto out_unref;
345 
346 	vm_obj = cdev_pager_allocate(bo, OBJT_MGTDEVICE, &ttm_pager_ops,
347 	    size, nprot, 0, curthread->td_ucred);
348 	if (vm_obj == NULL) {
349 		ret = -EINVAL;
350 		goto out_unref;
351 	}
352 	/*
353 	 * Note: We're transferring the bo reference to vm_obj->handle here.
354 	 */
355 	*offset = 0;
356 	*obj_res = vm_obj;
357 	return 0;
358 out_unref:
359 	ttm_bo_unref(&bo);
360 	return ret;
361 }
362 
363 void
364 ttm_bo_release_mmap(struct ttm_buffer_object *bo)
365 {
366 	vm_object_t vm_obj;
367 
368 	vm_obj = cdev_pager_lookup(bo);
369 	if (vm_obj != NULL) {
370 		cdev_mgtdev_pager_free_pages(vm_obj);
371 		vm_object_deallocate(vm_obj);
372 	}
373 }
374 
375 #if 0
376 int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
377 {
378 	if (vma->vm_pgoff != 0)
379 		return -EACCES;
380 
381 	vma->vm_ops = &ttm_bo_vm_ops;
382 	vma->vm_private_data = ttm_bo_reference(bo);
383 	vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
384 	return 0;
385 }
386 
387 ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
388 		  const char __user *wbuf, char __user *rbuf, size_t count,
389 		  loff_t *f_pos, bool write)
390 {
391 	struct ttm_buffer_object *bo;
392 	struct ttm_bo_driver *driver;
393 	struct ttm_bo_kmap_obj map;
394 	unsigned long dev_offset = (*f_pos >> PAGE_SHIFT);
395 	unsigned long kmap_offset;
396 	unsigned long kmap_end;
397 	unsigned long kmap_num;
398 	size_t io_size;
399 	unsigned int page_offset;
400 	char *virtual;
401 	int ret;
402 	bool no_wait = false;
403 	bool dummy;
404 
405 	read_lock(&bdev->vm_lock);
406 	bo = ttm_bo_vm_lookup_rb(bdev, dev_offset, 1);
407 	if (likely(bo != NULL))
408 		ttm_bo_reference(bo);
409 	read_unlock(&bdev->vm_lock);
410 
411 	if (unlikely(bo == NULL))
412 		return -EFAULT;
413 
414 	driver = bo->bdev->driver;
415 	if (unlikely(!driver->verify_access)) {
416 		ret = -EPERM;
417 		goto out_unref;
418 	}
419 
420 	ret = driver->verify_access(bo, filp);
421 	if (unlikely(ret != 0))
422 		goto out_unref;
423 
424 	kmap_offset = dev_offset - bo->vm_node->start;
425 	if (unlikely(kmap_offset >= bo->num_pages)) {
426 		ret = -EFBIG;
427 		goto out_unref;
428 	}
429 
430 	page_offset = *f_pos & ~PAGE_MASK;
431 	io_size = bo->num_pages - kmap_offset;
432 	io_size = (io_size << PAGE_SHIFT) - page_offset;
433 	if (count < io_size)
434 		io_size = count;
435 
436 	kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT;
437 	kmap_num = kmap_end - kmap_offset + 1;
438 
439 	ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
440 
441 	switch (ret) {
442 	case 0:
443 		break;
444 	case -EBUSY:
445 		ret = -EAGAIN;
446 		goto out_unref;
447 	default:
448 		goto out_unref;
449 	}
450 
451 	ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map);
452 	if (unlikely(ret != 0)) {
453 		ttm_bo_unreserve(bo);
454 		goto out_unref;
455 	}
456 
457 	virtual = ttm_kmap_obj_virtual(&map, &dummy);
458 	virtual += page_offset;
459 
460 	if (write)
461 		ret = copy_from_user(virtual, wbuf, io_size);
462 	else
463 		ret = copy_to_user(rbuf, virtual, io_size);
464 
465 	ttm_bo_kunmap(&map);
466 	ttm_bo_unreserve(bo);
467 	ttm_bo_unref(&bo);
468 
469 	if (unlikely(ret != 0))
470 		return -EFBIG;
471 
472 	*f_pos += io_size;
473 
474 	return io_size;
475 out_unref:
476 	ttm_bo_unref(&bo);
477 	return ret;
478 }
479 
480 ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf,
481 			char __user *rbuf, size_t count, loff_t *f_pos,
482 			bool write)
483 {
484 	struct ttm_bo_kmap_obj map;
485 	unsigned long kmap_offset;
486 	unsigned long kmap_end;
487 	unsigned long kmap_num;
488 	size_t io_size;
489 	unsigned int page_offset;
490 	char *virtual;
491 	int ret;
492 	bool no_wait = false;
493 	bool dummy;
494 
495 	kmap_offset = (*f_pos >> PAGE_SHIFT);
496 	if (unlikely(kmap_offset >= bo->num_pages))
497 		return -EFBIG;
498 
499 	page_offset = *f_pos & ~PAGE_MASK;
500 	io_size = bo->num_pages - kmap_offset;
501 	io_size = (io_size << PAGE_SHIFT) - page_offset;
502 	if (count < io_size)
503 		io_size = count;
504 
505 	kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT;
506 	kmap_num = kmap_end - kmap_offset + 1;
507 
508 	ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
509 
510 	switch (ret) {
511 	case 0:
512 		break;
513 	case -EBUSY:
514 		return -EAGAIN;
515 	default:
516 		return ret;
517 	}
518 
519 	ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map);
520 	if (unlikely(ret != 0)) {
521 		ttm_bo_unreserve(bo);
522 		return ret;
523 	}
524 
525 	virtual = ttm_kmap_obj_virtual(&map, &dummy);
526 	virtual += page_offset;
527 
528 	if (write)
529 		ret = copy_from_user(virtual, wbuf, io_size);
530 	else
531 		ret = copy_to_user(rbuf, virtual, io_size);
532 
533 	ttm_bo_kunmap(&map);
534 	ttm_bo_unreserve(bo);
535 	ttm_bo_unref(&bo);
536 
537 	if (unlikely(ret != 0))
538 		return ret;
539 
540 	*f_pos += io_size;
541 
542 	return io_size;
543 }
544 #endif
545