summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/drm/drm.h3
-rw-r--r--sys/dev/pci/drm/drmP.h7
-rw-r--r--sys/dev/pci/drm/drm_drv.c117
-rw-r--r--sys/dev/pci/drm/i915/i915_gem.c138
-rw-r--r--sys/uvm/uvm_device.c13
-rw-r--r--sys/uvm/uvm_device.h3
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 */