diff options
-rw-r--r-- | sys/dev/pci/drm/drm.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/drm/drmP.h | 7 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_drv.c | 117 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915/i915_gem.c | 138 | ||||
-rw-r--r-- | sys/uvm/uvm_device.c | 13 | ||||
-rw-r--r-- | sys/uvm/uvm_device.h | 3 |
6 files changed, 226 insertions, 55 deletions
diff --git a/sys/dev/pci/drm/drm.h b/sys/dev/pci/drm/drm.h index ab80f903c73..d4cfaf0d7a8 100644 --- a/sys/dev/pci/drm/drm.h +++ b/sys/dev/pci/drm/drm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: drm.h,v 1.10 2013/06/01 11:21:36 matthieu Exp $ */ +/* $OpenBSD: drm.h,v 1.11 2013/06/07 20:46:14 kettenis Exp $ */ /** * \file drm.h * Header for the Direct Rendering Manager @@ -175,6 +175,7 @@ enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ + _DRM_GEM = 6, /**< GEM object */ }; /** diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h index 9d89a785846..c387c27513a 100644 --- a/sys/dev/pci/drm/drmP.h +++ b/sys/dev/pci/drm/drmP.h @@ -1,4 +1,4 @@ -/* $OpenBSD: drmP.h,v 1.136 2013/03/28 23:47:37 jsg Exp $ */ +/* $OpenBSD: drmP.h,v 1.137 2013/06/07 20:46:14 kettenis Exp $ */ /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com */ @@ -497,6 +497,7 @@ struct drm_obj { SPLAY_ENTRY(drm_obj) entry; struct drm_device *dev; struct uvm_object *uao; + struct drm_local_map *map; size_t size; int name; @@ -924,6 +925,10 @@ void drm_unhold_object(struct drm_obj *); int drm_try_hold_object(struct drm_obj *); void drm_unhold_and_unref(struct drm_obj *); int drm_handle_create(struct drm_file *, struct drm_obj *, int *); + +void drm_gem_free_mmap_offset(struct drm_obj *obj); +int drm_gem_create_mmap_offset(struct drm_obj *obj); + struct drm_obj *drm_gem_object_lookup(struct drm_device *, struct drm_file *, int ); int drm_gem_close_ioctl(struct drm_device *, void *, struct drm_file *); diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c index 754637d8691..9a20f2103a4 100644 --- a/sys/dev/pci/drm/drm_drv.c +++ b/sys/dev/pci/drm/drm_drv.c @@ -1,4 +1,4 @@ -/* $OpenBSD: drm_drv.c,v 1.105 2013/04/22 08:31:46 mpi Exp $ */ +/* $OpenBSD: drm_drv.c,v 1.106 2013/06/07 20:46:15 kettenis Exp $ */ /*- * Copyright 2007-2009 Owain G. Ainsworth <oga@openbsd.org> * Copyright © 2008 Intel Corporation @@ -44,6 +44,7 @@ #include <sys/limits.h> #include <sys/systm.h> #include <uvm/uvm_extern.h> +#include <uvm/uvm_device.h> #include <sys/ttycom.h> /* for TIOCSGRP */ @@ -1737,6 +1738,120 @@ free: return (ret); } +/** + * drm_gem_free_mmap_offset - release a fake mmap offset for an object + * @obj: obj in question + * + * This routine frees fake offsets allocated by drm_gem_create_mmap_offset(). + */ +void +drm_gem_free_mmap_offset(struct drm_obj *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_local_map *map = obj->map; + + TAILQ_REMOVE(&dev->maplist, map, link); + obj->map = NULL; + + /* NOCOALESCE set, can't fail */ + extent_free(dev->handle_ext, map->ext, map->size, EX_NOWAIT); + + drm_free(map); +} + +/** + * drm_gem_create_mmap_offset - create a fake mmap offset for an object + * @obj: obj in question + * + * GEM memory mapping works by handing back to userspace a fake mmap offset + * it can use in a subsequent mmap(2) call. The DRM core code then looks + * up the object based on the offset and sets up the various memory mapping + * structures. + * + * This routine allocates and attaches a fake offset for @obj. + */ +int +drm_gem_create_mmap_offset(struct drm_obj *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_local_map *map; + int ret; + + /* Set the object up for mmap'ing */ + map = drm_calloc(1, sizeof(*map)); + if (map == NULL) + return -ENOMEM; + + map->flags = _DRM_DRIVER; + map->type = _DRM_GEM; + map->size = obj->size; + map->handle = obj; + + /* Get a DRM GEM mmap offset allocated... */ + ret = extent_alloc(dev->handle_ext, map->size, PAGE_SIZE, 0, + 0, EX_NOWAIT, &map->ext); + if (ret) { + DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); + ret = -ENOSPC; + goto out_free_list; + } + + TAILQ_INSERT_TAIL(&dev->maplist, map, link); + obj->map = map; + return 0; + +out_free_list: + drm_free(map); + + return ret; +} + +struct uvm_object * +udv_attach_drm(void *arg, vm_prot_t accessprot, voff_t off, vsize_t size) +{ + dev_t device = *((dev_t *)arg); + struct drm_device *dev = drm_get_device_from_kdev(kdev); + struct drm_local_map *map; + struct drm_obj *obj; + + if (cdevsw[major(device)].d_mmap != drmmmap) + return NULL; + + if (dev == NULL) + return NULL; + +again: + DRM_LOCK(); + TAILQ_FOREACH(map, &dev->maplist, link) { + if (off >= map->ext && off + size <= map->ext + map->size) + break; + } + + if (map == NULL || map->type != _DRM_GEM) { + DRM_UNLOCK(); + return NULL; + } + + obj = (struct drm_obj *)map->handle; + simple_lock(&uobj->vmobjlock); + if (obj->do_flags & DRM_BUSY) { + atomic_setbits_int(&obj->do_flags, DRM_WANTED); + simple_unlock(&uobj->vmobjlock); + DRM_UNLOCK(); + tsleep(obj, PVM, "udv_drm", 0); /* XXX msleep */ + goto again; + } +#ifdef DRMLOCKDEBUG + obj->holding_proc = curproc; +#endif + atomic_setbits_int(&obj->do_flags, DRM_BUSY); + simple_unlock(&obj->vmobjlock); + drm_ref(&obj->uobj); + drm_unhold_object(obj); + DRM_UNLOCK(); + return &obj->uobj; +} + int drm_handle_cmp(struct drm_handle *a, struct drm_handle *b) { diff --git a/sys/dev/pci/drm/i915/i915_gem.c b/sys/dev/pci/drm/i915/i915_gem.c index 42e87fc4c7d..2500793d2e2 100644 --- a/sys/dev/pci/drm/i915/i915_gem.c +++ b/sys/dev/pci/drm/i915/i915_gem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i915_gem.c,v 1.22 2013/05/27 19:29:25 kettenis Exp $ */ +/* $OpenBSD: i915_gem.c,v 1.23 2013/06/07 20:46:15 kettenis Exp $ */ /* * Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org> * @@ -82,6 +82,8 @@ int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, bool nonblocking); int i915_gem_wait_for_error(struct drm_device *); int __wait_seqno(struct intel_ring_buffer *, uint32_t, bool, struct timespec *); +int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *); +void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *); extern int ticks; @@ -624,13 +626,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (write_domain != 0 && read_domains != write_domain) return EINVAL; - /* - * Only allow GTT since that is all that we let userland near - * on OpenBSD. - */ - if ((write_domain | read_domains) & ~I915_GEM_DOMAIN_GTT) - return EINVAL; - ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -747,9 +742,11 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, * must free it in the case that the map fails. */ addr = 0; - ret = uvm_map(&curproc->p_vmspace->vm_map, &addr, nsize, &obj->uobj, + ret = uvm_map(&curproc->p_vmspace->vm_map, &addr, nsize, obj->uao, offset, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE, UVM_ADV_RANDOM, 0)); + if (ret == 0) + uao_reference(obj->uao); done: if (ret == 0) @@ -776,6 +773,9 @@ i915_gem_fault(struct drm_obj *gem_obj, struct uvm_faultinfo *ufi, dev_priv->entries++; + KASSERT(obj->base.map); + offset -= obj->base.map->ext; + if (rw_enter(&dev->dev_lock, RW_NOSLEEP | RW_READ) != 0) { uvmfault_unlockall(ufi, NULL, &obj->base.uobj, NULL); DRM_READLOCK(); @@ -980,62 +980,98 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, return i915_gem_get_gtt_size(dev, size, tiling_mode); } -// i915_gem_object_create_mmap_offset -// i915_gem_object_free_mmap_offset - int -i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *mmap_offset) +i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj; - struct drm_local_map *map; - voff_t offset; - vsize_t end, nsize; - int ret; +#if 0 + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; +#endif + int ret; - offset = (voff_t)*mmap_offset; + if (obj->base.map) + return 0; - obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); - if (obj == NULL) - return ENOENT; +#if 0 + dev_priv->mm.shrinker_no_lock_stealing = true; +#endif - /* Since we are doing purely uvm-related operations here we do - * not need to hold the object, a reference alone is sufficient + ret = drm_gem_create_mmap_offset(&obj->base); +#if 0 + if (ret != -ENOSPC) + goto out; + + /* Badly fragmented mmap space? The only way we can recover + * space is by destroying unwanted objects. We can't randomly release + * mmap_offsets as userspace expects them to be persistent for the + * lifetime of the objects. The closest we can is to release the + * offsets on purgeable objects by truncating it and marking it purged, + * which prevents userspace from ever using that object again. */ + i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT); + ret = drm_gem_create_mmap_offset(&obj->base); + if (ret != -ENOSPC) + goto out; - /* Check size. */ - if (offset > obj->base.size) { - ret = EINVAL; - goto done; + i915_gem_shrink_all(dev_priv); + ret = drm_gem_create_mmap_offset(&obj->base); +out: + dev_priv->mm.shrinker_no_lock_stealing = false; +#endif + + return ret; +} + +void +i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) +{ + if (!obj->base.map) + return; + + drm_gem_free_mmap_offset(&obj->base); +} + +int +i915_gem_mmap_gtt(struct drm_file *file, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; } - if (obj->madv != I915_MADV_WILLNEED) { - DRM_ERROR("Attempting to mmap a purgeable buffer\n"); - ret = EINVAL; - goto done; + if (obj->base.size > dev_priv->mm.gtt_mappable_end) { + ret = -E2BIG; + goto out; } - ret = i915_gem_object_bind_to_gtt(obj, 0, true, false); - if (ret) { - printf("%s: failed to bind\n", __func__); - goto done; + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to mmap a purgeable buffer\n"); + ret = -EINVAL; + goto out; } - i915_gem_object_move_to_inactive(obj); - end = round_page(offset + obj->base.size); - offset = trunc_page(offset); - nsize = end - offset; + ret = i915_gem_object_create_mmap_offset(obj); + if (ret) + goto out; - ret = drm_addmap(dev, offset + obj->gtt_offset, nsize, _DRM_AGP, - _DRM_WRITE_COMBINING, &map); - -done: - if (ret == 0) - *mmap_offset = map->ext; - else - drm_unref(&obj->base.uobj); + *offset = (u64)obj->base.map->ext; - return (ret); +out: + drm_gem_object_unreference(&obj->base); +unlock: + DRM_UNLOCK(); + return ret; } /** @@ -1068,6 +1104,8 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj) { DRM_ASSERT_HELD(&obj->base); + i915_gem_object_free_mmap_offset(obj); + simple_lock(&obj->base.uao->vmobjlock); obj->base.uao->pgops->pgo_flush(obj->base.uao, 0, obj->base.size, PGO_ALLPAGES | PGO_FREE); diff --git a/sys/uvm/uvm_device.c b/sys/uvm/uvm_device.c index 9d9a2cdac38..316d932d2cf 100644 --- a/sys/uvm/uvm_device.c +++ b/sys/uvm/uvm_device.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_device.c,v 1.42 2013/05/30 16:29:46 tedu Exp $ */ +/* $OpenBSD: uvm_device.c,v 1.43 2013/06/07 20:46:14 kettenis Exp $ */ /* $NetBSD: uvm_device.c,v 1.30 2000/11/25 06:27:59 chs Exp $ */ /* @@ -50,6 +50,8 @@ #include <uvm/uvm.h> #include <uvm/uvm_device.h> +#include "drm.h" + /* * private global data structure * @@ -104,6 +106,9 @@ udv_attach(void *arg, vm_prot_t accessprot, voff_t off, vsize_t size) dev_t device = *((dev_t *)arg); struct uvm_device *udv, *lcv; paddr_t (*mapfn)(dev_t, off_t, int); +#if NDRM > 0 + struct uvm_object *obj; +#endif /* * before we do anything, ensure this device supports mmap @@ -122,6 +127,12 @@ udv_attach(void *arg, vm_prot_t accessprot, voff_t off, vsize_t size) if (off < 0) return(NULL); +#if NDRM > 0 + obj = udv_attach_drm(arg, accessprot, off, size); + if (obj) + return(obj); +#endif + /* * Check that the specified range of the device allows the * desired protection. diff --git a/sys/uvm/uvm_device.h b/sys/uvm/uvm_device.h index e31455e8102..03bc37df44f 100644 --- a/sys/uvm/uvm_device.h +++ b/sys/uvm/uvm_device.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_device.h,v 1.8 2002/03/14 01:27:18 millert Exp $ */ +/* $OpenBSD: uvm_device.h,v 1.9 2013/06/07 20:46:14 kettenis Exp $ */ /* $NetBSD: uvm_device.h,v 1.9 2000/05/28 10:21:55 drochner Exp $ */ /* @@ -71,6 +71,7 @@ struct uvm_device { */ struct uvm_object *udv_attach(void *, vm_prot_t, voff_t, vsize_t); +struct uvm_object *udv_attach_drm(void *, vm_prot_t, voff_t, vsize_t); #endif /* _KERNEL */ |