Module Name:    src
Committed By:   riastradh
Date:           Fri Feb 14 04:38:24 UTC 2020

Modified Files:
        src/sys/external/bsd/drm2/dist/drm/amd/amdgpu: amdgpu_cs.c amdgpu_gem.c
            amdgpu_ttm.c
        src/sys/external/bsd/drm2/dist/drm/radeon: radeon_cs.c radeon_gem.c
            radeon_ttm.c

Log Message:
Implement drm userptr with uvm_vslock & bus_dmamap_load_uio.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 \
    src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c
cvs rdiff -u -r1.5 -r1.6 \
    src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c
cvs rdiff -u -r1.4 -r1.5 \
    src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c
cvs rdiff -u -r1.4 -r1.5 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c
cvs rdiff -u -r1.7 -r1.8 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c
cvs rdiff -u -r1.15 -r1.16 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c
diff -u src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c:1.3 src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c:1.3	Mon Aug 27 14:04:50 2018
+++ src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c	Fri Feb 14 04:38:23 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdgpu_cs.c,v 1.3 2018/08/27 14:04:50 riastradh Exp $	*/
+/*	$NetBSD: amdgpu_cs.c,v 1.4 2020/02/14 04:38:23 riastradh Exp $	*/
 
 /*
  * Copyright 2008 Jerome Glisse.
@@ -27,7 +27,7 @@
  *    Jerome Glisse <[email protected]>
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_cs.c,v 1.3 2018/08/27 14:04:50 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_cs.c,v 1.4 2020/02/14 04:38:23 riastradh Exp $");
 
 #include <linux/list_sort.h>
 #include <drm/drmP.h>
@@ -406,7 +406,7 @@ static int amdgpu_cs_parser_relocs(struc
 	struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
 	struct amdgpu_cs_buckets buckets;
 	struct list_head duplicates;
-	bool need_mmap_lock __diagused = false;
+	bool need_mmap_lock = false;
 	int i, r;
 
 	if (p->bo_list) {
@@ -426,9 +426,8 @@ static int amdgpu_cs_parser_relocs(struc
 		list_add(&p->uf_entry.tv.head, &p->validated);
 
 #ifdef __NetBSD__
-	KASSERTMSG(!need_mmap_lock,
-	    "someone didn't finish adding support for userptr"
-	    " and it wasn't me");
+	if (need_mmap_lock)
+		vm_map_lock_read(&curproc->p_vmspace->vm_map);
 #else
 	if (need_mmap_lock)
 		down_read(&current->mm->mmap_sem);
@@ -450,7 +449,10 @@ error_validate:
 		ttm_eu_backoff_reservation(&p->ticket, &p->validated);
 
 error_reserve:
-#ifndef __NetBSD__
+#ifdef __NetBSD__
+	if (need_mmap_lock)
+		vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 	if (need_mmap_lock)
 		up_read(&current->mm->mmap_sem);
 #endif

Index: src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c
diff -u src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c:1.5 src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c:1.6
--- src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c:1.5	Fri Feb 14 04:35:19 2020
+++ src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c	Fri Feb 14 04:38:23 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdgpu_gem.c,v 1.5 2020/02/14 04:35:19 riastradh Exp $	*/
+/*	$NetBSD: amdgpu_gem.c,v 1.6 2020/02/14 04:38:23 riastradh Exp $	*/
 
 /*
  * Copyright 2008 Advanced Micro Devices, Inc.
@@ -28,7 +28,7 @@
  *          Jerome Glisse
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_gem.c,v 1.5 2020/02/14 04:35:19 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_gem.c,v 1.6 2020/02/14 04:38:23 riastradh Exp $");
 
 #include <linux/ktime.h>
 #include <drm/drmP.h>
@@ -228,15 +228,6 @@ error_unlock:
 int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *filp)
 {
-#ifdef __NetBSD__
-	/*
-	 * XXX Too painful to contemplate for now.  If you add this,
-	 * make sure to update amdgpu_cs.c amdgpu_cs_parser_relocs
-	 * (need_mmap_lock), and anything else using
-	 * amdgpu_ttm_tt_has_userptr.
-	 */
-	return -ENODEV;
-#else
 	struct amdgpu_device *adev = dev->dev_private;
 	struct drm_amdgpu_gem_userptr *args = data;
 	struct drm_gem_object *gobj;
@@ -281,17 +272,29 @@ int amdgpu_gem_userptr_ioctl(struct drm_
 	}
 
 	if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) {
+#ifdef __NetBSD__
+		vm_map_lock_read(&curproc->p_vmspace->vm_map);
+#else
 		down_read(&current->mm->mmap_sem);
+#endif
 		r = amdgpu_bo_reserve(bo, true);
 		if (r) {
+#ifdef __NetBSD__
+			vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 			up_read(&current->mm->mmap_sem);
+#endif
 			goto release_object;
 		}
 
 		amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT);
 		r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
 		amdgpu_bo_unreserve(bo);
+#ifdef __NetBSD__
+		vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 		up_read(&current->mm->mmap_sem);
+#endif
 		if (r)
 			goto release_object;
 	}
@@ -312,7 +315,6 @@ handle_lockup:
 	r = amdgpu_gem_handle_lockup(adev, r);
 
 	return r;
-#endif
 }
 
 int amdgpu_mode_dumb_mmap(struct drm_file *filp,

Index: src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c
diff -u src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c:1.4 src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c:1.5
--- src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c:1.4	Mon Aug 27 15:22:54 2018
+++ src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c	Fri Feb 14 04:38:23 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdgpu_ttm.c,v 1.4 2018/08/27 15:22:54 riastradh Exp $	*/
+/*	$NetBSD: amdgpu_ttm.c,v 1.5 2020/02/14 04:38:23 riastradh Exp $	*/
 
 /*
  * Copyright 2009 Jerome Glisse.
@@ -32,7 +32,7 @@
  *    Dave Airlie
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_ttm.c,v 1.4 2018/08/27 15:22:54 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_ttm.c,v 1.5 2020/02/14 04:38:23 riastradh Exp $");
 
 #include <ttm/ttm_bo_api.h>
 #include <ttm/ttm_bo_driver.h>
@@ -488,39 +488,119 @@ struct amdgpu_ttm_tt {
 	struct amdgpu_device		*adev;
 	u64				offset;
 	uint64_t			userptr;
+#ifdef __NetBSD__
+	struct vmspace			*usermm;
+#else
 	struct mm_struct		*usermm;
+#endif
 	uint32_t			userflags;
 };
 
 /* prepare the sg table with the user pages */
 static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 {
-#ifdef __NetBSD__
-	panic("we don't handle user pointers round these parts");
-#else
 	struct amdgpu_device *adev = amdgpu_get_adev(ttm->bdev);
 	struct amdgpu_ttm_tt *gtt = (void *)ttm;
+#ifndef __NetBSD__
 	unsigned pinned = 0, nents;
+#endif
 	int r;
 
 	int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+#ifndef __NetBSD__
 	enum dma_data_direction direction = write ?
 		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+#endif
 
+#ifdef __NetBSD__
+	if (curproc->p_vmspace != gtt->usermm)
+		return -EPERM;
+#else
 	if (current->mm != gtt->usermm)
 		return -EPERM;
+#endif
 
 	if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
 		/* check that we only pin down anonymous memory
 		   to prevent problems with writeback */
 		unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
+#ifdef __NetBSD__
+		/* XXX ???  TOCTOU, anyone?  */
+		/* XXX should do range_test */
+		struct vm_map_entry *entry;
+		bool ok;
+		vm_map_lock_read(&gtt->usermm->vm_map);
+		ok = uvm_map_lookup_entry(&gtt->usermm->vm_map,
+		    (vaddr_t)gtt->userptr, &entry);
+		if (ok)
+			ok = !UVM_ET_ISOBJ(entry) && end <= entry->end;
+		vm_map_unlock_read(&gtt->usermm->vm_map);
+		if (!ok)
+			return -EPERM;
+#else
 		struct vm_area_struct *vma;
 
 		vma = find_vma(gtt->usermm, gtt->userptr);
 		if (!vma || vma->vm_file || vma->vm_end < end)
 			return -EPERM;
+#endif
+	}
+
+#ifdef __NetBSD__
+	struct iovec iov = {
+		.iov_base = (void *)(vaddr_t)gtt->userptr,
+		.iov_len = ttm->num_pages << PAGE_SHIFT,
+	};
+	struct uio uio = {
+		.uio_iov = &iov,
+		.uio_iovcnt = 1,
+		.uio_offset = 0,
+		.uio_resid = ttm->num_pages << PAGE_SHIFT,
+		.uio_rw = (write ? UIO_READ : UIO_WRITE), /* XXX ??? */
+		.uio_vmspace = gtt->usermm,
+	};
+	unsigned long i;
+
+	/* Wire the relevant part of the user's address space.  */
+	/* XXX What happens if user does munmap?  */
+	/* XXX errno NetBSD->Linux */
+	r = -uvm_vslock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT,
+	    (write ? VM_PROT_WRITE : VM_PROT_READ)); /* XXX ??? */
+	if (r)
+		goto fail0;
+
+	/* Load it up for DMA.  */
+	/* XXX errno NetBSD->Linux */
+	r = -bus_dmamap_load_uio(adev->ddev->dmat, gtt->ttm.dma_address, &uio,
+	    BUS_DMA_WAITOK);
+	if (r)
+		goto fail1;
+
+	/* Get each of the pages as ttm requests.  */
+	for (i = 0; i < ttm->num_pages; i++) {
+		vaddr_t va = (vaddr_t)gtt->userptr + (i << PAGE_SHIFT);
+		paddr_t pa;
+		struct vm_page *vmp;
+
+		if (!pmap_extract(gtt->usermm->vm_map.pmap, va, &pa)) {
+			r = -EFAULT;
+			goto fail2;
+		}
+		vmp = PHYS_TO_VM_PAGE(pa);
+		ttm->pages[i] = container_of(vmp, struct page, p_vmp);
 	}
 
+	/* Success!  */
+	return 0;
+
+fail2:	while (i --> 0)
+		ttm->pages[i] = NULL; /* paranoia */
+	bus_dmamap_unload(adev->ddev->dmat, gtt->ttm.dma_address);
+fail1:	uvm_vsunlock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT);
+fail0:	return r;
+#else
 	do {
 		unsigned num_pages = ttm->num_pages - pinned;
 		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
@@ -563,7 +643,13 @@ release_pages:
 static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
 {
 #ifdef __NetBSD__
-	panic("some varmint pinned a userptr to my hat");
+	struct amdgpu_device *adev = amdgpu_get_adev(ttm->bdev);
+	struct amdgpu_ttm_tt *gtt = container_of(ttm, struct amdgpu_ttm_tt,
+	    ttm.ttm);
+
+	bus_dmamap_unload(adev->ddev->dmat, gtt->ttm.dma_address);
+	uvm_vsunlock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT);
 #else
 	struct amdgpu_device *adev = amdgpu_get_adev(ttm->bdev);
 	struct amdgpu_ttm_tt *gtt = (void *)ttm;
@@ -696,16 +782,16 @@ static int amdgpu_ttm_tt_populate(struct
 
 	if (gtt && gtt->userptr) {
 #ifdef __NetBSD__
-		panic("don't point at users, it's not polite");
+		ttm->sg = NULL;
 #else
 		ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
 		if (!ttm->sg)
 			return -ENOMEM;
+#endif
 
 		ttm->page_flags |= TTM_PAGE_FLAG_SG;
 		ttm->state = tt_unbound;
 		return 0;
-#endif
 	}
 
 	if (slave && ttm->sg) {
@@ -823,19 +909,19 @@ static const struct uvm_pagerops amdgpu_
 int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
 			      uint32_t flags)
 {
-#ifdef __NetBSD__
-	return -ENODEV;
-#else
 	struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
 	if (gtt == NULL)
 		return -EINVAL;
 
 	gtt->userptr = addr;
+#ifdef __NetBSD__
+	gtt->usermm = curproc->p_vmspace;
+#else
 	gtt->usermm = current->mm;
+#endif
 	gtt->userflags = flags;
 	return 0;
-#endif
 }
 
 bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm)

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c:1.4 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c:1.5
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c:1.4	Mon Aug 27 13:58:04 2018
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c	Fri Feb 14 04:38:24 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_cs.c,v 1.4 2018/08/27 13:58:04 riastradh Exp $	*/
+/*	$NetBSD: radeon_cs.c,v 1.5 2020/02/14 04:38:24 riastradh Exp $	*/
 
 /*
  * Copyright 2008 Jerome Glisse.
@@ -27,7 +27,7 @@
  *    Jerome Glisse <[email protected]>
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_cs.c,v 1.4 2018/08/27 13:58:04 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_cs.c,v 1.5 2020/02/14 04:38:24 riastradh Exp $");
 
 #include <linux/list_sort.h>
 #include <drm/drmP.h>
@@ -83,7 +83,7 @@ static int radeon_cs_parser_relocs(struc
 	struct radeon_cs_chunk *chunk;
 	struct radeon_cs_buckets buckets;
 	unsigned i;
-	bool need_mmap_lock __diagused = false;
+	bool need_mmap_lock = false;
 	int r;
 
 	if (p->chunk_relocs == NULL) {
@@ -182,9 +182,8 @@ static int radeon_cs_parser_relocs(struc
 		p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
 					      &p->validated);
 #ifdef __NetBSD__
-	KASSERTMSG(!need_mmap_lock,
-	    "someone didn't finish adding support for userptr"
-	    " and it wasn't me");
+	if (need_mmap_lock)
+		vm_map_lock_read(&curproc->p_vmspace->vm_map);
 #else
 	if (need_mmap_lock)
 		down_read(&current->mm->mmap_sem);
@@ -192,7 +191,10 @@ static int radeon_cs_parser_relocs(struc
 
 	r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
 
-#ifndef __NetBSD__
+#ifdef __NetBSD__
+	if (need_mmap_lock)
+		vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 	if (need_mmap_lock)
 		up_read(&current->mm->mmap_sem);
 #endif

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c:1.7 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c:1.8
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c:1.7	Fri Feb 14 04:35:20 2020
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c	Fri Feb 14 04:38:24 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_gem.c,v 1.7 2020/02/14 04:35:20 riastradh Exp $	*/
+/*	$NetBSD: radeon_gem.c,v 1.8 2020/02/14 04:38:24 riastradh Exp $	*/
 
 /*
  * Copyright 2008 Advanced Micro Devices, Inc.
@@ -28,7 +28,7 @@
  *          Jerome Glisse
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_gem.c,v 1.7 2020/02/14 04:35:20 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_gem.c,v 1.8 2020/02/14 04:38:24 riastradh Exp $");
 
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
@@ -290,15 +290,6 @@ int radeon_gem_create_ioctl(struct drm_d
 int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *filp)
 {
-#ifdef __NetBSD__
-	/*
-	 * XXX Too painful to contemplate for now.  If you add this,
-	 * make sure to update radeon_cs.c radeon_cs_parser_relocs
-	 * (need_mmap_lock), and anything else using
-	 * radeon_ttm_tt_has_userptr.
-	 */
-	return -ENODEV;
-#else
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_radeon_gem_userptr *args = data;
 	struct drm_gem_object *gobj;
@@ -349,17 +340,29 @@ int radeon_gem_userptr_ioctl(struct drm_
 	}
 
 	if (args->flags & RADEON_GEM_USERPTR_VALIDATE) {
+#ifdef __NetBSD__
+		vm_map_lock_read(&curproc->p_vmspace->vm_map);
+#else
 		down_read(&current->mm->mmap_sem);
+#endif
 		r = radeon_bo_reserve(bo, true);
 		if (r) {
+#ifdef __NetBSD__
+			vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 			up_read(&current->mm->mmap_sem);
+#endif
 			goto release_object;
 		}
 
 		radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_GTT);
 		r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
 		radeon_bo_unreserve(bo);
+#ifdef __NetBSD__
+		vm_map_unlock_read(&curproc->p_vmspace->vm_map);
+#else
 		up_read(&current->mm->mmap_sem);
+#endif
 		if (r)
 			goto release_object;
 	}
@@ -382,7 +385,6 @@ handle_lockup:
 	r = radeon_gem_handle_lockup(rdev, r);
 
 	return r;
-#endif
 }
 
 int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.15 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.16
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.15	Mon Aug 27 15:22:54 2018
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c	Fri Feb 14 04:38:24 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_ttm.c,v 1.15 2018/08/27 15:22:54 riastradh Exp $	*/
+/*	$NetBSD: radeon_ttm.c,v 1.16 2020/02/14 04:38:24 riastradh Exp $	*/
 
 /*
  * Copyright 2009 Jerome Glisse.
@@ -32,7 +32,7 @@
  *    Dave Airlie
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_ttm.c,v 1.15 2018/08/27 15:22:54 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_ttm.c,v 1.16 2020/02/14 04:38:24 riastradh Exp $");
 
 #include <ttm/ttm_bo_api.h>
 #include <ttm/ttm_bo_driver.h>
@@ -546,38 +546,118 @@ struct radeon_ttm_tt {
 	u64				offset;
 
 	uint64_t			userptr;
+#ifdef __NetBSD__
+	struct vmspace			*usermm;
+#else
 	struct mm_struct		*usermm;
+#endif
 	uint32_t			userflags;
 };
 
 /* prepare the sg table with the user pages */
 static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 {
-#ifdef __NetBSD__
-	panic("we don't handle user pointers round these parts");
-#else
 	struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
 	struct radeon_ttm_tt *gtt = (void *)ttm;
+#ifndef __NetBSD__
 	unsigned pinned = 0, nents;
+#endif
 	int r;
 
 	int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
+#ifndef __NetBSD__
 	enum dma_data_direction direction = write ?
 		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+#endif
 
+#ifdef __NetBSD__
+	if (curproc->p_vmspace != gtt->usermm)
+		return -EPERM;
+#else
 	if (current->mm != gtt->usermm)
 		return -EPERM;
+#endif
 
 	if (gtt->userflags & RADEON_GEM_USERPTR_ANONONLY) {
 		/* check that we only pin down anonymous memory
 		   to prevent problems with writeback */
 		unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
+#ifdef __NetBSD__
+		/* XXX ???  TOCTOU, anyone?  */
+		/* XXX should do range_test */
+		struct vm_map_entry *entry;
+		bool ok;
+		vm_map_lock_read(&gtt->usermm->vm_map);
+		ok = uvm_map_lookup_entry(&gtt->usermm->vm_map,
+		    (vaddr_t)gtt->userptr, &entry);
+		if (ok)
+			ok = !UVM_ET_ISOBJ(entry) && end <= entry->end;
+		vm_map_unlock_read(&gtt->usermm->vm_map);
+		if (!ok)
+			return -EPERM;
+#else
 		struct vm_area_struct *vma;
 		vma = find_vma(gtt->usermm, gtt->userptr);
 		if (!vma || vma->vm_file || vma->vm_end < end)
 			return -EPERM;
+#endif
 	}
 
+#ifdef __NetBSD__
+	struct iovec iov = {
+		.iov_base = (void *)(vaddr_t)gtt->userptr,
+		.iov_len = ttm->num_pages << PAGE_SHIFT,
+	};
+	struct uio uio = {
+		.uio_iov = &iov,
+		.uio_iovcnt = 1,
+		.uio_offset = 0,
+		.uio_resid = ttm->num_pages << PAGE_SHIFT,
+		.uio_rw = (write ? UIO_READ : UIO_WRITE), /* XXX ??? */
+		.uio_vmspace = gtt->usermm,
+	};
+	unsigned long i;
+
+	/* Wire the relevant part of the user's address space.  */
+	/* XXX What happens if user does munmap?  */
+	/* XXX errno NetBSD->Linux */
+	r = -uvm_vslock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT,
+	    (write ? VM_PROT_WRITE : VM_PROT_READ)); /* XXX ??? */
+	if (r)
+		goto fail0;
+
+	/* Load it up for DMA.  */
+	/* XXX errno NetBSD->Linux */
+	r = -bus_dmamap_load_uio(rdev->ddev->dmat, gtt->ttm.dma_address, &uio,
+	    BUS_DMA_WAITOK);
+	if (r)
+		goto fail1;
+
+	/* Get each of the pages as ttm requests.  */
+	for (i = 0; i < ttm->num_pages; i++) {
+		vaddr_t va = (vaddr_t)gtt->userptr + (i << PAGE_SHIFT);
+		paddr_t pa;
+		struct vm_page *vmp;
+
+		if (!pmap_extract(gtt->usermm->vm_map.pmap, va, &pa)) {
+			r = -EFAULT;
+			goto fail2;
+		}
+		vmp = PHYS_TO_VM_PAGE(pa);
+		ttm->pages[i] = container_of(vmp, struct page, p_vmp);
+	}
+
+	/* Success!  */
+	return 0;
+
+fail2:	while (i --> 0)
+		ttm->pages[i] = NULL; /* paranoia */
+	bus_dmamap_unload(rdev->ddev->dmat, gtt->ttm.dma_address);
+fail1:	uvm_vsunlock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT);
+fail0:	return r;
+#else
 	do {
 		unsigned num_pages = ttm->num_pages - pinned;
 		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
@@ -620,7 +700,12 @@ release_pages:
 static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
 {
 #ifdef __NetBSD__
-	panic("some varmint pinned a userptr to my hat");
+	struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+	struct radeon_ttm_tt *gtt = (void *)ttm;
+
+	bus_dmamap_unload(rdev->ddev->dmat, gtt->ttm.dma_address);
+	uvm_vsunlock(gtt->usermm, (void *)(vaddr_t)gtt->userptr,
+	    ttm->num_pages << PAGE_SHIFT);
 #else
 	struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
 	struct radeon_ttm_tt *gtt = (void *)ttm;
@@ -758,15 +843,15 @@ static int radeon_ttm_tt_populate(struct
 
 	if (gtt && gtt->userptr) {
 #ifdef __NetBSD__
-		panic("don't point at users, it's not polite");
+		ttm->sg = NULL;
 #else
 		ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
 		if (!ttm->sg)
 			return -ENOMEM;
+#endif
 
 		ttm->page_flags |= TTM_PAGE_FLAG_SG;
 		ttm->state = tt_unbound;
-#endif
 		return 0;
 	}
 
@@ -903,25 +988,19 @@ static const struct uvm_pagerops radeon_
 int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
 			      uint32_t flags)
 {
-#ifdef __NetBSD__
-	/*
-	 * XXX Too painful to contemplate for now.  If you add this,
-	 * make sure to update radeon_cs.c radeon_cs_parser_relocs
-	 * (need_mmap_lock), and anything else using
-	 * radeon_ttm_tt_has_userptr.
-	 */
-	return -ENODEV;
-#else
 	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
 
 	if (gtt == NULL)
 		return -EINVAL;
 
 	gtt->userptr = addr;
+#ifdef __NetBSD__
+	gtt->usermm = curproc->p_vmspace;
+#else
 	gtt->usermm = current->mm;
+#endif
 	gtt->userflags = flags;
 	return 0;
-#endif
 }
 
 bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)

Reply via email to