diff options
-rw-r--r-- | include/drm/i915_drm.h | 17 | ||||
-rw-r--r-- | intel/intel_bufmgr.c | 10 | ||||
-rw-r--r-- | intel/intel_bufmgr.h | 4 | ||||
-rw-r--r-- | intel/intel_bufmgr_gem.c | 135 | ||||
-rw-r--r-- | intel/intel_bufmgr_priv.h | 11 |
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. * |