summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTvrtko Ursulin <tvrtko.ursulin@intel.com>2014-02-26 16:41:41 +0000
committerBen Widawsky <benjamin.widawsky@linux.intel.com>2014-05-01 14:46:00 -0700
commit57b4fe98e2d3b3be2f14cde186bc980bcc6bc8c2 (patch)
tree53e669f9e0d5da73f62dfc42684ac4a0ec8c42f5
parentbb1f4263b7ce169ab484b8463f0bf630a1ab4f2b (diff)
libdrm_intel: Add support for userptr objectsuserptr
Allow userptr objects to be created and used via libdrm_intel. At the moment tiling and mapping to GTT aperture is not supported due hardware limitations across different generations and uncertainty about its usefulness. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v1) Signed-off-by: Ben Widawsky <benjamin.widawsky@linux.intel.com>
-rw-r--r--include/drm/i915_drm.h17
-rw-r--r--intel/intel_bufmgr.c10
-rw-r--r--intel/intel_bufmgr.h4
-rw-r--r--intel/intel_bufmgr_gem.c135
-rw-r--r--intel/intel_bufmgr_priv.h11
5 files changed, 175 insertions, 2 deletions
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 2f4eb8ce0..669ef75f6 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -223,6 +223,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_GEM_GET_CACHING 0x30
#define DRM_I915_REG_READ 0x31
#define DRM_I915_GET_RESET_STATS 0x32
+#define DRM_I915_GEM_USERPTR 0x34
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -273,6 +274,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
#define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats)
+#define DRM_IOCTL_I915_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -498,6 +500,21 @@ struct drm_i915_gem_mmap_gtt {
__u64 offset;
};
+struct drm_i915_gem_userptr {
+ __u64 user_ptr;
+ __u64 user_size;
+ __u32 flags;
+#define I915_USERPTR_READ_ONLY (1<<0)
+#define I915_GPU_MIRRORED (1<<1)
+#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
+ /**
+ * Returned handle for the object.
+ *
+ * Object handles are nonzero.
+ */
+ __u32 handle;
+};
+
struct drm_i915_gem_set_domain {
/** Handle for the object */
__u32 handle;
diff --git a/intel/intel_bufmgr.c b/intel/intel_bufmgr.c
index 905556f64..fd1db736e 100644
--- a/intel/intel_bufmgr.c
+++ b/intel/intel_bufmgr.c
@@ -60,6 +60,16 @@ drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment);
}
+drm_intel_bo *drm_intel_bo_alloc_userptr(drm_intel_bufmgr *bufmgr,
+ const char *name, void *addr,
+ uint64_t size,
+ uint32_t flags)
+{
+ if (bufmgr->bo_alloc_userptr)
+ return bufmgr->bo_alloc_userptr(bufmgr, name, addr, size, flags);
+ return NULL;
+}
+
drm_intel_bo *
drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
int x, int y, int cpp, uint32_t *tiling_mode,
diff --git a/intel/intel_bufmgr.h b/intel/intel_bufmgr.h
index 9383c722e..104845e7a 100644
--- a/intel/intel_bufmgr.h
+++ b/intel/intel_bufmgr.h
@@ -113,6 +113,10 @@ drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
+drm_intel_bo *drm_intel_bo_alloc_userptr(drm_intel_bufmgr *bufmgr,
+ const char *name, void *addr,
+ uint64_t size,
+ uint32_t flags);
drm_intel_bo *drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr,
const char *name,
int x, int y, int cpp,
diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c
index 007a6d86c..e62026197 100644
--- a/intel/intel_bufmgr_gem.c
+++ b/intel/intel_bufmgr_gem.c
@@ -51,6 +51,8 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
#include <stdbool.h>
#include "errno.h"
@@ -221,6 +223,11 @@ struct _drm_intel_bo_gem {
bool idle;
/**
+ * Boolean of whether this buffer was allocated with userptr
+ */
+ bool is_userptr;
+
+ /**
* Size in bytes of this buffer and its relocation descendents.
*
* Used to avoid costly tree walking in
@@ -847,6 +854,70 @@ drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
tiling, stride);
}
+static drm_intel_bo *
+drm_intel_gem_bo_alloc_userptr(drm_intel_bufmgr *bufmgr,
+ const char *name,
+ void *addr,
+ uint64_t size,
+ uint32_t flags)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
+ drm_intel_bo_gem *bo_gem;
+ int ret;
+ struct drm_i915_gem_userptr userptr;
+
+ bo_gem = calloc(1, sizeof(*bo_gem));
+ if (!bo_gem)
+ return NULL;
+
+ bo_gem->bo.size = size;
+
+ VG_CLEAR(userptr);
+ userptr.user_ptr = (__u64)((unsigned long)addr);
+ userptr.user_size = size;
+ userptr.flags = flags;
+
+ ret = drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_USERPTR,
+ &userptr);
+ if (ret != 0) {
+ DBG("bo_create_userptr:"
+ " ioctl failed with user ptr %p size 0x%" PRIx64
+ " user flags 0x%x\n", addr, size, flags);
+ free(bo_gem);
+ return NULL;
+ }
+
+ bo_gem->gem_handle = userptr.handle;
+ bo_gem->bo.handle = bo_gem->gem_handle;
+ bo_gem->bo.bufmgr = bufmgr;
+ bo_gem->is_userptr = true;
+ bo_gem->bo.virtual = addr;
+ /* Save the address provided by user */
+ bo_gem->mem_virtual = addr;
+ bo_gem->tiling_mode = I915_TILING_NONE;
+ bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+ bo_gem->stride = 0;
+
+ DRMINITLISTHEAD(&bo_gem->name_list);
+ DRMINITLISTHEAD(&bo_gem->vma_list);
+
+ bo_gem->name = name;
+ atomic_set(&bo_gem->refcount, 1);
+ bo_gem->validate_index = -1;
+ bo_gem->reloc_tree_fences = 0;
+ bo_gem->used_as_reloc_target = false;
+ bo_gem->has_error = false;
+ bo_gem->reusable = false;
+
+ drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
+
+ DBG("bo_create_userptr: ptr %p buf %d (%s) size %ldb\n",
+ addr, bo_gem->gem_handle, bo_gem->name, size);
+
+ return &bo_gem->bo;
+}
+
/**
* Returns a drm_intel_bo wrapping the given buffer object handle.
*
@@ -1241,6 +1312,9 @@ map_gtt(drm_intel_bo *bo)
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
int ret;
+ if (bo_gem->is_userptr)
+ return -EINVAL;
+
if (bo_gem->map_count++ == 0)
drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
@@ -1385,13 +1459,18 @@ int drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo)
static int drm_intel_gem_bo_unmap(drm_intel_bo *bo)
{
- drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bufmgr_gem *bufmgr_gem;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
int ret = 0;
if (bo == NULL)
return 0;
+ if (bo_gem->is_userptr)
+ return 0;
+
+ bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+
pthread_mutex_lock(&bufmgr_gem->lock);
if (bo_gem->map_count <= 0) {
@@ -1449,6 +1528,9 @@ drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset,
struct drm_i915_gem_pwrite pwrite;
int ret;
+ if (bo_gem->is_userptr)
+ return -EINVAL;
+
VG_CLEAR(pwrite);
pwrite.handle = bo_gem->gem_handle;
pwrite.offset = offset;
@@ -1501,6 +1583,9 @@ drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
struct drm_i915_gem_pread pread;
int ret;
+ if (bo_gem->is_userptr)
+ return -EINVAL;
+
VG_CLEAR(pread);
pread.handle = bo_gem->gem_handle;
pread.offset = offset;
@@ -2460,6 +2545,12 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
int ret;
+ /* Tiling with userptr surfaces is not supported
+ * on all hardware so refuse it for time being.
+ */
+ if (bo_gem->is_userptr)
+ return -EINVAL;
+
/* Linear buffers have no stride. By ensuring that we only ever use
* stride 0 with linear buffers, we simplify our code.
*/
@@ -3181,6 +3272,44 @@ drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo,
bo_gem->aub_annotation_count = count;
}
+static bool
+has_userptr(int fd)
+{
+ int ret;
+ void *ptr;
+ long pgsz;
+ struct drm_i915_gem_userptr userptr;
+ struct drm_gem_close close_bo;
+
+ pgsz = sysconf(_SC_PAGESIZE);
+ assert(ret > 0);
+
+ ret = posix_memalign(&ptr, pgsz, pgsz);
+ assert(ret == 0);
+
+ memset(&userptr, 0, sizeof(userptr));
+ userptr.user_ptr = (__u64)(unsigned long)ptr;
+ userptr.user_size = pgsz;
+
+retry:
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr);
+ if (ret) {
+ if (errno == ENODEV && userptr.flags == 0) {
+ userptr.flags = I915_USERPTR_UNSYNCHRONIZED;
+ goto retry;
+ }
+ free(ptr);
+ return false;
+ }
+
+ close_bo.handle = userptr.handle;
+ ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+ assert(ret == 0);
+ free(ptr);
+
+ return true;
+}
+
/**
* Initializes the GEM buffer manager, which uses the kernel to allocate, map,
* and manage map buffer objections.
@@ -3273,6 +3402,10 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
bufmgr_gem->has_relaxed_fencing = ret == 0;
+ if (has_userptr(fd))
+ bufmgr_gem->bufmgr.bo_alloc_userptr =
+ drm_intel_gem_bo_alloc_userptr;
+
gp.param = I915_PARAM_HAS_WAIT_TIMEOUT;
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
bufmgr_gem->has_wait_timeout = ret == 0;
diff --git a/intel/intel_bufmgr_priv.h b/intel/intel_bufmgr_priv.h
index 2592d42d5..5b9dc6e5d 100644
--- a/intel/intel_bufmgr_priv.h
+++ b/intel/intel_bufmgr_priv.h
@@ -60,7 +60,16 @@ struct _drm_intel_bufmgr {
const char *name,
unsigned long size,
unsigned int alignment);
-
+ /**
+ * Allocate a buffer object from an existing user accessible
+ * address malloc'd with the provided size.
+ * Alignment is used when mapping to the gtt.
+ * Flags may be I915_VMAP_READ_ONLY I915_GPU_MIRRORED or I915_USERPTR_UNSYNCHRONIZED
+ */
+ drm_intel_bo *(*bo_alloc_userptr)(drm_intel_bufmgr *bufmgr,
+ const char *name, void *addr,
+ uint64_t size,
+ uint32_t flags);
/**
* Allocate a tiled buffer object.
*