From 8f1f2a4f550dfa23f914a10798b8a44c66cd541b Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Sun, 9 Feb 2020 15:56:04 +0000 Subject: [PATCH] WIP: drm userptr --- .../bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c | 12 +- .../bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c | 22 ++-- .../bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c | 104 +++++++++++++++-- .../bsd/drm2/dist/drm/radeon/radeon_cs.c | 12 +- .../bsd/drm2/dist/drm/radeon/radeon_gem.c | 22 ++-- .../bsd/drm2/dist/drm/radeon/radeon_ttm.c | 109 +++++++++++++++--- sys/external/bsd/drm2/radeon/files.radeon | 1 + 7 files changed, 226 insertions(+), 56 deletions(-) diff --git a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c index b132b6121a68..f0b638d7a908 100644 --- a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c +++ b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cs.c @@ -406,7 +406,7 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p) 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(struct amdgpu_cs_parser *p) 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(¤t->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(¤t->mm->mmap_sem); #endif diff --git a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c index 6ce61e435392..071475be0b35 100644 --- a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c +++ b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_gem.c @@ -226,15 +226,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; @@ -279,17 +270,29 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, } if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) { +#ifdef __NetBSD__ + vm_map_lock_read(&curproc->p_vmspace->vm_map); +#else down_read(¤t->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(¤t->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(¤t->mm->mmap_sem); +#endif if (r) goto release_object; } @@ -310,7 +313,6 @@ handle_lockup: r = amdgpu_gem_handle_lockup(adev, r); return r; -#endif } int amdgpu_mode_dumb_mmap(struct drm_file *filp, diff --git a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c index 981739962bfa..c47ce4e336dc 100644 --- a/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c +++ b/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ttm.c @@ -488,39 +488,117 @@ 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(>t->usermm->vm_map); + ok = uvm_map_lookup_entry(>t->usermm->vm_map, + (vaddr_t)gtt->userptr, &entry); + if (ok) + ok = !UVM_ET_ISOBJ(entry) && end <= entry->end; + vm_map_unlock_read(>t->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)) + 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 +641,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 +780,16 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm) 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 +907,19 @@ static const struct uvm_pagerops amdgpu_uvm_ops = { 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) diff --git a/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c b/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c index 8f98b18070ec..b1a726b11669 100644 --- a/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c +++ b/sys/external/bsd/drm2/dist/drm/radeon/radeon_cs.c @@ -83,7 +83,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) 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(struct radeon_cs_parser *p) 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(¤t->mm->mmap_sem); @@ -192,7 +191,10 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) 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(¤t->mm->mmap_sem); #endif diff --git a/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c b/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c index fcdd98388ddc..ac0ad18b9a25 100644 --- a/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c +++ b/sys/external/bsd/drm2/dist/drm/radeon/radeon_gem.c @@ -288,15 +288,6 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, 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; @@ -347,17 +338,29 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, } if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { +#ifdef __NetBSD__ + vm_map_lock_read(&curproc->p_vmspace->vm_map); +#else down_read(¤t->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(¤t->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(¤t->mm->mmap_sem); +#endif if (r) goto release_object; } @@ -380,7 +383,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, diff --git a/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c b/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c index 2d18eefb2cd9..19543c0a27b5 100644 --- a/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c +++ b/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c @@ -546,38 +546,116 @@ 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(>t->usermm->vm_map); + ok = uvm_map_lookup_entry(>t->usermm->vm_map, + (vaddr_t)gtt->userptr, &entry); + if (ok) + ok = !UVM_ET_ISOBJ(entry) && end <= entry->end; + vm_map_unlock_read(>t->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)) + 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 +698,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 +841,15 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) 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 +986,19 @@ static const struct uvm_pagerops radeon_uvm_ops = { 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) diff --git a/sys/external/bsd/drm2/radeon/files.radeon b/sys/external/bsd/drm2/radeon/files.radeon index 84727d964c61..0949d2d8b8c9 100644 --- a/sys/external/bsd/drm2/radeon/files.radeon +++ b/sys/external/bsd/drm2/radeon/files.radeon @@ -88,6 +88,7 @@ file external/bsd/drm2/dist/drm/radeon/radeon_kv_smc.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_legacy_encoders.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_legacy_tv.c radeon +#file external/bsd/drm2/dist/drm/radeon/radeon_mn.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_ni.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_ni_dma.c radeon file external/bsd/drm2/dist/drm/radeon/radeon_ni_dpm.c radeon