diff --git a/sys/dev/drm/core/drm_vm.c b/sys/dev/drm/core/drm_vm.c index 6687c6c2a14b..b79a039f3d77 100644 --- a/sys/dev/drm/core/drm_vm.c +++ b/sys/dev/drm/core/drm_vm.c @@ -370,6 +370,7 @@ static const struct vm_operations_struct drm_vm_ops = { .fault = drm_vm_fault, .open = drm_vm_open, .close = drm_vm_close, + .objtype = OBJT_MGTDEVICE, }; /** Shared virtual memory operations */ @@ -377,6 +378,7 @@ static const struct vm_operations_struct drm_vm_shm_ops = { .fault = drm_vm_shm_fault, .open = drm_vm_open, .close = drm_vm_shm_close, + .objtype = OBJT_MGTDEVICE, }; /** DMA virtual memory operations */ @@ -384,6 +386,7 @@ static const struct vm_operations_struct drm_vm_dma_ops = { .fault = drm_vm_dma_fault, .open = drm_vm_open, .close = drm_vm_close, + .objtype = OBJT_MGTDEVICE, }; /** Scatter-gather virtual memory operations */ diff --git a/sys/dev/drm/drmkpi/include/linux/mm.h b/sys/dev/drm/drmkpi/include/linux/mm.h index 069b2d996ea3..7986b4e39cf6 100644 --- a/sys/dev/drm/drmkpi/include/linux/mm.h +++ b/sys/dev/drm/drmkpi/include/linux/mm.h @@ -119,20 +119,18 @@ struct vm_area_struct { struct vm_fault { unsigned int flags; pgoff_t pgoff; - union { - /* user-space address */ - void *virtual_address; /* < 4.11 */ - unsigned long address; /* >= 4.11 */ - }; + vm_object_t object; + vm_pindex_t pindex; /* fault pindex */ + int count; /* pages faulted in */ struct page *page; - struct vm_area_struct *vma; }; struct vm_operations_struct { void (*open) (struct vm_area_struct *); void (*close) (struct vm_area_struct *); - int (*fault) (struct vm_area_struct *, struct vm_fault *); + int (*fault) (struct vm_fault *); int (*access) (struct vm_area_struct *, unsigned long, void *, int, int); + int objtype; }; struct sysinfo { diff --git a/sys/dev/drm/freebsd/drm_gem_cma_helper.c b/sys/dev/drm/freebsd/drm_gem_cma_helper.c index 441b7c92c25b..8c71a83de56f 100644 --- a/sys/dev/drm/freebsd/drm_gem_cma_helper.c +++ b/sys/dev/drm/freebsd/drm_gem_cma_helper.c @@ -156,9 +156,8 @@ drm_gem_cma_alloc(struct drm_device *drm, struct drm_gem_cma_object *bo) } static int -drm_gem_cma_fault(struct vm_area_struct *dummy, struct vm_fault *vmf) +drm_gem_cma_fault(struct vm_fault *vmf) { - struct vm_area_struct *vma; struct drm_gem_object *gem_obj; struct drm_gem_cma_object *bo; vm_object_t obj; @@ -166,15 +165,14 @@ drm_gem_cma_fault(struct vm_area_struct *dummy, struct vm_fault *vmf) struct page *page; int i; - vma = vmf->vma; - gem_obj = vma->vm_private_data; + obj = vmf->object; + gem_obj = obj->handle; bo = container_of(gem_obj, struct drm_gem_cma_object, gem_obj); - obj = vma->vm_obj; if (!bo->m) return (VM_FAULT_SIGBUS); - pidx = OFF_TO_IDX(vmf->address - vma->vm_start); + pidx = vmf->pindex; if (pidx >= bo->npages) return (VM_FAULT_SIGBUS); @@ -191,9 +189,8 @@ drm_gem_cma_fault(struct vm_area_struct *dummy, struct vm_fault *vmf) } VM_OBJECT_WUNLOCK(obj); - vma->vm_pfn_first = 0; - vma->vm_pfn_count = bo->npages; - DRM_DEBUG("%s: pidx: %llu, start: 0x%08X, addr: 0x%08lX\n", __func__, pidx, vma->vm_start, vmf->address); + vmf->pindex = 0; + vmf->count = bo->npages; return (VM_FAULT_NOPAGE); @@ -209,6 +206,7 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = { .fault = drm_gem_cma_fault, .open = drm_gem_vm_open, .close = drm_gem_vm_close, + .objtype = OBJT_MGTDEVICE, }; static int diff --git a/sys/dev/drm/freebsd/drm_os_freebsd.c b/sys/dev/drm/freebsd/drm_os_freebsd.c index 15bf679505ff..1653a60ff8fe 100644 --- a/sys/dev/drm/freebsd/drm_os_freebsd.c +++ b/sys/dev/drm/freebsd/drm_os_freebsd.c @@ -24,10 +24,13 @@ */ #include +#include +#include #include -#include #include -#include +#include +#include +#include #include #include @@ -277,9 +280,22 @@ drm_fstub_ioctl(struct file *file, u_long cmd, void *data, struct ucred *cred, return (ENXIO); } -static struct rwlock drm_vma_lock; -RW_SYSINIT(drm_freebsd, &drm_vma_lock, "drmcompat-vma-lock"); -static TAILQ_HEAD(, vm_area_struct) drm_vma_head = +/* + * Glue between a VM object, DRM GEM object (referenced via object->handle), and + * mappings of said VM object. The FreeBSD VM fault handler gives us very + * little visibility into the mappings of the object, so this list of vmas is + * not really used. + */ +struct drm_object_glue { + vm_object_t object; + const struct vm_operations_struct *ops; + TAILQ_HEAD(, vm_area_struct) vmas; /* existing mappings */ + TAILQ_ENTRY(drm_object_glue) link; /* global list linkage */ +}; + +static struct sx drm_vma_lock; +SX_SYSINIT(drm_freebsd, &drm_vma_lock, "drmcompat-vma-lock"); +static TAILQ_HEAD(, drm_object_glue) drm_vma_head = TAILQ_HEAD_INITIALIZER(drm_vma_head); static void @@ -288,28 +304,6 @@ drm_vmap_free(struct vm_area_struct *vmap) kfree(vmap); } -static void -drm_vmap_remove(struct vm_area_struct *vmap) -{ - rw_wlock(&drm_vma_lock); - TAILQ_REMOVE(&drm_vma_head, vmap, vm_entry); - rw_wunlock(&drm_vma_lock); -} - -static struct vm_area_struct * -drm_vmap_find(void *handle) -{ - struct vm_area_struct *vmap; - - rw_rlock(&drm_vma_lock); - TAILQ_FOREACH(vmap, &drm_vma_head, vm_entry) { - if (vmap->vm_private_data == handle) - break; - } - rw_runlock(&drm_vma_lock); - return (vmap); -} - static int drm_cdev_pager_fault(vm_object_t vm_obj __unused, vm_ooffset_t offset __unused, int prot __unused, vm_page_t *mres __unused) @@ -321,38 +315,38 @@ static int drm_cdev_pager_populate(vm_object_t vm_obj, vm_pindex_t pidx, int fault_type, vm_prot_t max_prot, vm_pindex_t *first, vm_pindex_t *last) { - struct vm_area_struct *vmap; + struct vm_fault vmf; + struct drm_object_glue *dog; int err; - /* get VM area structure */ - vmap = drm_vmap_find(vm_obj->handle); - MPASS(vmap != NULL); - MPASS(vmap->vm_private_data == vm_obj->handle); - VM_OBJECT_WUNLOCK(vm_obj); - if (unlikely(vmap->vm_ops == NULL)) { + sx_slock(&drm_vma_lock); + TAILQ_FOREACH(dog, &drm_vma_head, link) { + if (dog->object->handle == vm_obj->handle) + break; + } + sx_sunlock(&drm_vma_lock); + MPASS(dog != NULL); + + if (unlikely(dog->ops == NULL)) { err = VM_FAULT_SIGBUS; } else { - struct vm_fault vmf; - - /* fill out VM fault structure */ - vmf.virtual_address = (void *)(uintptr_t)IDX_TO_OFF(pidx); + vmf.object = vm_obj; + vmf.pindex = pidx; vmf.flags = (fault_type & VM_PROT_WRITE) ? FAULT_FLAG_WRITE : 0; vmf.pgoff = 0; vmf.page = NULL; - vmf.vma = vmap; - - vmap->vm_pfn_count = 0; - vmap->vm_obj = vm_obj; + vmf.count = 0; - err = vmap->vm_ops->fault(vmap, &vmf); + err = dog->ops->fault(&vmf); - while (vmap->vm_pfn_count == 0 && err == VM_FAULT_NOPAGE) { + while (vmf.count == 0 && err == VM_FAULT_NOPAGE) { kern_yield(PRI_USER); - err = vmap->vm_ops->fault(vmap, &vmf); + err = dog->ops->fault(&vmf); } } + VM_OBJECT_WLOCK(vm_obj); /* translate return code */ switch (err) { @@ -369,15 +363,14 @@ drm_cdev_pager_populate(vm_object_t vm_obj, vm_pindex_t pidx, int fault_type, * found in the object, it will simply xbusy the first * page and return with vm_pfn_count set to 1. */ - *first = vmap->vm_pfn_first; - *last = *first + vmap->vm_pfn_count - 1; + *first = vmf.pindex; + *last = *first + vmf.count - 1; err = VM_PAGER_OK; break; default: err = VM_PAGER_ERROR; break; } - VM_OBJECT_WLOCK(vm_obj); return (err); } @@ -385,8 +378,6 @@ static int drm_cdev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred, u_short *color) { - - MPASS(drm_vmap_find(handle) != NULL); *color = 0; return (0); } @@ -394,33 +385,47 @@ drm_cdev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, static void drm_cdev_pager_dtor(void *handle) { - const struct vm_operations_struct *vm_ops; - struct vm_area_struct *vmap; - - vmap = drm_vmap_find(handle); - MPASS(vmap != NULL); + struct vm_area_struct *vma, *vma1; + struct drm_object_glue *dog; - /* - * Remove handle before calling close operation to prevent - * other threads from reusing the handle pointer. - */ - drm_vmap_remove(vmap); - - vm_ops = vmap->vm_ops; - if (likely(vm_ops != NULL)) - vm_ops->close(vmap); + sx_xlock(&drm_vma_lock); + TAILQ_FOREACH(dog, &drm_vma_head, link) { + if (dog->object->handle == handle) + break; + } + MPASS(dog != NULL); + TAILQ_REMOVE(&drm_vma_head, dog, link); + sx_xunlock(&drm_vma_lock); + + MPASS(!TAILQ_EMPTY(&dog->vmas)); + TAILQ_FOREACH_SAFE(vma, &dog->vmas, vm_entry, vma1) { + TAILQ_REMOVE(&dog->vmas, vma, vm_entry); + vma->vm_ops->close(vma); + drm_vmap_free(vma); + } + kfree(dog); +} - drm_vmap_free(vmap); +static void +drm_phys_pager_dtor(vm_object_t object) +{ + drm_cdev_pager_dtor(object->handle); } -static struct cdev_pager_ops drm_mgtdev_pg_ops = { +static const struct phys_pager_ops drm_phys_pg_objs = { + /* OBJT_PHYS */ + .phys_pg_populate = drm_cdev_pager_populate, + .phys_pg_dtor = drm_phys_pager_dtor +}; + +static const struct cdev_pager_ops drm_mgtdev_pg_ops = { /* OBJT_MGTDEVICE */ .cdev_pg_populate = drm_cdev_pager_populate, .cdev_pg_ctor = drm_cdev_pager_ctor, .cdev_pg_dtor = drm_cdev_pager_dtor }; -static struct cdev_pager_ops drm_dev_pg_ops = { +static const struct cdev_pager_ops drm_dev_pg_ops = { /* OBJT_DEVICE */ .cdev_pg_fault = drm_cdev_pager_fault, .cdev_pg_ctor = drm_cdev_pager_ctor, @@ -454,9 +459,8 @@ drm_fstub_do_mmap(struct file *file, const struct file_operations *fops, attr = pgprot2cachemode(vmap->vm_page_prot); if (vmap->vm_ops != NULL) { - struct vm_area_struct *ptr; - void *vm_private_data; - bool vm_no_fault; + struct drm_object_glue *dog; + void *handle; if (vmap->vm_ops->open == NULL || vmap->vm_ops->close == NULL || @@ -466,62 +470,47 @@ drm_fstub_do_mmap(struct file *file, const struct file_operations *fops, return (EINVAL); } - vm_private_data = vmap->vm_private_data; + handle = vmap->vm_private_data; - rw_wlock(&drm_vma_lock); - TAILQ_FOREACH(ptr, &drm_vma_head, vm_entry) { - if (ptr->vm_private_data == vm_private_data) + sx_xlock(&drm_vma_lock); + TAILQ_FOREACH(dog, &drm_vma_head, link) { + if (dog->object->handle == handle) break; } - /* check if there is an existing VM area struct */ - if (ptr != NULL) { - /* check if the VM area structure is invalid */ - if (ptr->vm_ops == NULL || - ptr->vm_ops->open == NULL || - ptr->vm_ops->close == NULL) { - rv = ESTALE; - vm_no_fault = 1; - } else { - rv = EEXIST; - vm_no_fault = (ptr->vm_ops->fault == NULL); - } - } else { - /* insert VM area structure into list */ - TAILQ_INSERT_TAIL(&drm_vma_head, vmap, vm_entry); - rv = 0; - vm_no_fault = (vmap->vm_ops->fault == NULL); - } - rw_wunlock(&drm_vma_lock); - - if (rv != 0) { - /* free allocated VM area struct */ - drm_vmap_free(vmap); - /* check for stale VM area struct */ - if (rv != EEXIST) - return (rv); - } - - /* check if there is no fault handler */ - if (vm_no_fault) { - *obj = cdev_pager_allocate(vm_private_data, - OBJT_DEVICE, &drm_dev_pg_ops, size, prot, - *foff, td->td_ucred); + if (dog != NULL) { + KASSERT(dog->ops == vmap->vm_ops, + ("mismatched vm_ops")); + TAILQ_INSERT_HEAD(&dog->vmas, vmap, vm_entry); + *obj = dog->object; + vm_object_reference(*obj); } else { - *obj = cdev_pager_allocate(vm_private_data, - OBJT_MGTDEVICE, &drm_mgtdev_pg_ops, size, prot, - *foff, td->td_ucred); - } - - /* check if allocating the VM object failed */ - if (*obj == NULL) { - if (rv == 0) { - /* remove VM area struct from list */ - drm_vmap_remove(vmap); - /* free allocated VM area struct */ - drm_vmap_free(vmap); + switch (vmap->vm_ops->objtype) { + case OBJT_DEVICE: + case OBJT_MGTDEVICE: + *obj = cdev_pager_allocate(handle, + vmap->vm_ops->objtype, + vmap->vm_ops->objtype == OBJT_DEVICE ? + &drm_dev_pg_ops : &drm_mgtdev_pg_ops, + size, prot, *foff, td->td_ucred); + break; + case OBJT_PHYS: + *obj = phys_pager_allocate(handle, + &drm_phys_pg_objs, NULL, size, prot, *foff, + td->td_ucred); + break; + default: + __assert_unreachable(); } - return (EINVAL); + dog = kzalloc(sizeof(*dog), GFP_KERNEL); + dog->object = *obj; + dog->ops = vmap->vm_ops; + TAILQ_INIT(&dog->vmas); + + TAILQ_INSERT_HEAD(&dog->vmas, vmap, vm_entry); + TAILQ_INSERT_HEAD(&drm_vma_head, dog, link); } + vmap->vm_obj = dog->object; + sx_xunlock(&drm_vma_lock); } else { struct sglist *sg; diff --git a/sys/dev/drm/panfrost/panfrost_gem.c b/sys/dev/drm/panfrost/panfrost_gem.c index 0017411d4688..4d2c76265a76 100644 --- a/sys/dev/drm/panfrost/panfrost_gem.c +++ b/sys/dev/drm/panfrost/panfrost_gem.c @@ -95,8 +95,6 @@ panfrost_gem_free_object(struct drm_gem_object *obj) continue; vm_page_lock(m); - m->flags &= ~PG_FICTITIOUS; - m->oflags |= VPO_UNMANAGED; vm_page_unwire_noq(m); vm_page_free(m); vm_page_unlock(m); @@ -287,7 +285,7 @@ sgt_get_page_by_idx(struct sg_table *sgt, int pidx) } static vm_fault_t -panfrost_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +panfrost_gem_fault(struct vm_fault *vmf) { struct panfrost_gem_object *bo; struct drm_gem_object *gem_obj; @@ -296,12 +294,12 @@ panfrost_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vm_pindex_t pidx; vm_object_t obj; - obj = vma->vm_obj; - gem_obj = vma->vm_private_data; + obj = vmf->object; + gem_obj = obj->handle; bo = (struct panfrost_gem_object *)gem_obj; sc = gem_obj->dev->dev_private; - pidx = OFF_TO_IDX(vmf->virtual_address); + pidx = vmf->pindex; retry: VM_OBJECT_WLOCK(obj); @@ -332,9 +330,7 @@ panfrost_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vm_page_valid(page); VM_OBJECT_WUNLOCK(obj); - vma->vm_pfn_first = pidx; - vma->vm_pfn_count = 1; - + vmf->count = 1; return (VM_FAULT_NOPAGE); fail_unlock: @@ -360,6 +356,7 @@ static const struct vm_operations_struct panfrost_gem_vm_ops = { .fault = panfrost_gem_fault, .open = panfrost_gem_vm_open, .close = panfrost_gem_vm_close, + .objtype = OBJT_PHYS, }; int @@ -615,8 +612,6 @@ panfrost_alloc_pages_iommu(struct panfrost_gem_object *bo) va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); cpu_dcache_wb_range((void *)va, PAGE_SIZE); m->valid = VM_PAGE_BITS_ALL; - m->oflags &= ~VPO_UNMANAGED; - m->flags |= PG_FICTITIOUS; bo->pages[i] = m; } @@ -664,8 +659,6 @@ panfrost_alloc_pages_contig(struct panfrost_gem_object *bo) va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); cpu_dcache_wb_range((void *)va, PAGE_SIZE); m->valid = VM_PAGE_BITS_ALL; - m->oflags &= ~VPO_UNMANAGED; - m->flags |= PG_FICTITIOUS; bo->pages[i] = m; m++; }