Okay this is my first public efforts at the i915 driver superioctl.

Please review and give out about anything I missed, I'm sure the error handling needs "some work". But I thought I'd get it out there..

I have a Mesa side to this in my personal mesa tree (i915-superioctl branch) but I just want to review the DRM side first.

Regards,
Dave.

--
David Airlie, Software Engineer
http://www.skynet.ie/~airlied / airlied at skynet.ie
Linux kernel - DRI, VAX / pam_smb / ILUG
diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c
index 75763e7..4ea0478 100644
--- a/linux-core/i915_buffer.c
+++ b/linux-core/i915_buffer.c
@@ -42,7 +42,7 @@ int i915_fence_types(struct drm_buffer_object *bo,
 		     uint32_t * fclass,
 		     uint32_t * type)
 {
-	if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE))
+	if ((bo->mem.mask | bo->mem.flags) & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE))
 		*type = 3;
 	else
 		*type = 1;
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 3a9ecab..58f6735 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -725,6 +725,338 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
 	return 0;
 }
 
+struct i915_relocatee_info {
+	struct drm_buffer_object *buf;
+	unsigned long offset;
+	u32 *data_page;
+	unsigned page_offset;
+	struct drm_bo_kmap_obj kmap;
+	int is_iomem;
+};
+
+static void i915_dereference_buffers_locked(struct drm_buffer_object **buffers,
+					    unsigned num_buffers)
+{
+	while (num_buffers--)
+		drm_bo_usage_deref_locked(&buffers[num_buffers]);
+}
+
+int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
+		     struct drm_buffer_object **buffers,
+		     struct i915_relocatee_info *relocatee,
+		     uint32_t *reloc)
+{
+	unsigned index;
+	unsigned long new_cmd_offset;
+	u32 val;
+	int ret;
+
+	if (reloc[2] >= num_buffers) {
+		DRM_ERROR("Illegal relocation buffer %08X\n", reloc[2]);
+		return -EINVAL;
+	}
+
+	new_cmd_offset = reloc[0];
+	if (!relocatee->data_page ||
+	    !drm_bo_same_page(relocatee->offset, new_cmd_offset)) {
+		drm_bo_kunmap(&relocatee->kmap);
+		relocatee->offset = new_cmd_offset;
+		ret = drm_bo_kmap(relocatee->buf, new_cmd_offset >> PAGE_SHIFT,
+				  1, &relocatee->kmap);
+		if (ret) {
+			DRM_ERROR("Could not map command buffer to apply relocs\n %08x", new_cmd_offset);
+			return ret;
+		}
+
+		relocatee->data_page = drm_bmo_virtual(&relocatee->kmap,
+						       &relocatee->is_iomem);
+		relocatee->page_offset = (relocatee->offset & PAGE_MASK);
+	}
+
+	val = buffers[reloc[2]]->offset;
+	index = (reloc[0] - relocatee->page_offset) >> 2;
+
+	/* add in validate */
+	val = val + reloc[1];
+
+	relocatee->data_page[index] = val;
+	return 0;
+}
+
+#define RELOC_START_OFFSET 2
+#define RELOC_NUM_INTS 3
+int i915_process_relocs(struct drm_file *file_priv,
+			uint32_t buf_handle,
+			uint32_t *reloc_buf_handle,
+			struct i915_relocatee_info *relocatee,
+			struct drm_buffer_object **buffers,
+			uint32_t num_buffers)
+{
+     	struct drm_device *dev = file_priv->head->dev;
+	struct drm_buffer_object *reloc_list_object;
+	int ret;
+	uint32_t cur_handle = *reloc_buf_handle;
+	uint32_t num_relocs;
+	struct drm_bo_kmap_obj reloc_kmap;
+	uint32_t *reloc_page;
+	int reloc_is_iomem;
+	uint32_t reloc_offset, reloc_end, reloc_page_offset, next_offset;
+	int reloc_stride;
+	uint32_t cur_offset;
+
+	memset(&reloc_kmap, 0, sizeof(reloc_kmap));
+
+	reloc_list_object = drm_lookup_buffer_object(file_priv, cur_handle, 1);
+	if (!reloc_list_object)
+		return -EINVAL;
+
+	ret = drm_bo_kmap(reloc_list_object, 0, 1, &reloc_kmap);
+	if (ret) {
+		DRM_ERROR("Could not map relocation buffer.\n");
+		goto out;
+	}
+
+	reloc_page = drm_bmo_virtual(&reloc_kmap, &reloc_is_iomem);
+	num_relocs = reloc_page[0] & 0xffff;
+
+	if ((reloc_page[0] >> 16) & 0xffff) {
+		DRM_ERROR("Unsupported relocation type requested\n");
+		goto out;
+	}
+
+	/* get next relocate buffer handle */
+	*reloc_buf_handle = reloc_page[1];
+	reloc_stride = 4; /* may be different for other types of relocs */
+
+	DRM_DEBUG("num relocs is %d, next is %08X\n", num_relocs, reloc_page[1]);
+
+	reloc_page_offset = 0;
+	reloc_offset = 4 * sizeof(uint32_t);
+	reloc_end = reloc_offset + (num_relocs * reloc_stride * sizeof(uint32_t));
+
+	do {
+		next_offset = drm_bo_offset_end(reloc_offset, reloc_end);
+
+		do {
+			cur_offset = ((reloc_offset + reloc_page_offset) & ~PAGE_MASK) / sizeof(uint32_t);
+			ret = i915_apply_reloc(file_priv, num_buffers,
+					 buffers, relocatee, &reloc_page[cur_offset]);
+			if (ret)
+				goto out;
+
+			reloc_offset += reloc_stride * sizeof(uint32_t);
+		} while(reloc_offset < next_offset);
+
+		drm_bo_kunmap(&reloc_kmap);
+
+		reloc_offset = next_offset;
+		if (reloc_offset != reloc_end) {
+			ret = drm_bo_kmap(reloc_list_object, reloc_offset >> PAGE_SHIFT, 1, &reloc_kmap);
+			if (ret){
+				DRM_ERROR("Could not map relocation buffer.\n");
+				goto out;
+			}
+			
+			reloc_page = drm_bmo_virtual(&reloc_kmap, &reloc_is_iomem);
+			reloc_page_offset = reloc_offset & ~PAGE_MASK;
+		}
+
+	} while (reloc_offset != reloc_end);
+out:
+	drm_bo_kunmap(&reloc_kmap);
+
+	mutex_lock(&dev->struct_mutex);
+	drm_bo_usage_deref_locked(&reloc_list_object);
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+/*
+ * Validate, add fence and relocate a block of bos from a userspace list 
+ */
+int i915_validate_buffer_list(struct drm_file *file_priv,
+			      unsigned int fence_class, uint64_t data,
+			      struct drm_buffer_object **buffers,
+			      uint32_t *num_buffers)
+{
+	struct drm_i915_op_arg arg;
+	struct drm_bo_op_req *req = &arg.d.req;
+	struct drm_bo_arg_rep rep;
+	unsigned long next = 0;
+	int ret = 0;
+	unsigned buf_count = 0;
+     	struct drm_device *dev = file_priv->head->dev;
+	uint32_t buf_reloc_handle, buf_handle;
+	struct i915_relocatee_info relocatee;
+
+	do {
+		if (buf_count >= *num_buffers) {
+			DRM_ERROR("Buffer count exceeded %d\n.", *num_buffers);
+			ret = -EINVAL;
+			goto out_err;
+		}
+
+		buffers[buf_count] = NULL;
+
+		if (copy_from_user(&arg, (void __user *)(unsigned)data, sizeof(arg))) {
+			ret = -EFAULT;
+			goto out_err;
+		}
+
+		if (arg.handled) {
+			data = arg.next;
+			buffers[buf_count] = drm_lookup_buffer_object(file_priv, req->arg_handle, 1);
+			buf_count++;
+			continue;
+		}
+
+		rep.ret = 0;
+		if (req->op != drm_bo_validate) {
+			DRM_ERROR
+			    ("Buffer object operation wasn't \"validate\".\n");
+			rep.ret = -EINVAL;
+			goto out_err;
+		}
+
+		buf_handle = req->bo_req.handle;
+		buf_reloc_handle = arg.reloc_handle;
+		
+		rep.ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
+						 req->bo_req.fence_class,
+						 req->bo_req.flags,
+						 req->bo_req.mask,
+						 req->bo_req.hint,
+						 &rep.bo_info,
+						 &buffers[buf_count]);
+		
+		if (rep.ret) {
+			DRM_ERROR("error on handle validate %d\n", rep.ret);
+			goto out_err;
+		}
+
+
+		next = arg.next;
+		arg.handled = 1;
+		arg.d.rep = rep;
+		
+		if (copy_to_user((void __user *)(unsigned)data, &arg, sizeof(arg)))
+			return -EFAULT;
+
+		data = next;
+		buf_count++;
+		
+		if (buf_reloc_handle) {
+			memset(&relocatee, 0, sizeof(relocatee));
+
+			relocatee.buf = drm_lookup_buffer_object(file_priv, buf_handle, 1);
+			if (!relocatee.buf) {
+				DRM_DEBUG("relocatee buffer invalid %08x\n", buf_handle);
+				ret = -EINVAL;
+				goto out_err;
+			}
+			
+			while (buf_reloc_handle) {
+				ret = i915_process_relocs(file_priv, buf_handle, &buf_reloc_handle, &relocatee, buffers, buf_count);
+				if (ret) {
+					DRM_ERROR("process relocs failed\n");
+					break;
+				}
+			}
+
+			drm_bo_kunmap(&relocatee.kmap);
+			mutex_lock(&dev->struct_mutex);
+			drm_bo_usage_deref_locked(&relocatee.buf);
+			mutex_unlock(&dev->struct_mutex);
+			
+			if (ret)
+				goto out_err;
+
+		}
+	} while (next != 0);
+	*num_buffers = buf_count;
+	return 0;
+out_err:
+	mutex_lock(&dev->struct_mutex);
+	i915_dereference_buffers_locked(buffers, buf_count);
+	mutex_unlock(&dev->struct_mutex);
+	*num_buffers = 0;
+	return (ret) ? ret : rep.ret;
+}
+
+
+
+
+static int i915_execbuffer(struct drm_device *dev, void *data,
+			   struct drm_file *file_priv)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
+		dev_priv->sarea_priv;
+	struct drm_i915_execbuffer *exec_buf = data;
+	struct _drm_i915_batchbuffer *batch = &exec_buf->batch;
+	struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
+	int num_buffers;
+	int ret;
+	struct drm_fence_object *fence;
+
+	if (!dev_priv->allow_batchbuffer) {
+		DRM_ERROR("Batchbuffer ioctl disabled\n");
+		return -EINVAL;
+	}
+
+	
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
+							batch->num_cliprects *
+							sizeof(struct drm_clip_rect)))
+		return -EFAULT;	
+
+	num_buffers = I915_NUM_VALIDATE_BUFFERS;
+
+	/* validate buffer list + fixup relocations */
+	ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list, dev_priv->buffers, &num_buffers);
+	if (ret)
+		return ret;
+
+	/* submit buffer */
+	batch->start = dev_priv->buffers[num_buffers-1]->offset;
+
+	DRM_DEBUG("i915 exec batchbuffer, start %x used %d cliprects %d\n",
+		  batch->start, batch->used, batch->num_cliprects);
+
+	ret = i915_dispatch_batchbuffer(dev, batch);
+	if (ret)
+		goto out_err0;
+
+	sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+	
+	/* fence */
+	ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence);
+	if (ret)
+		goto out_err0;
+	
+	if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) {
+		ret = drm_fence_add_user_object(file_priv, fence, fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE);
+		if (!ret) {
+			fence_arg->handle = fence->base.hash.key;
+			fence_arg->fence_class = fence->fence_class;
+			fence_arg->type = fence->type;
+			fence_arg->signaled = fence->signaled;
+		}
+	}
+	drm_fence_usage_deref_unlocked(&fence);
+out_err0:
+
+	/* handle errors */
+	mutex_lock(&dev->struct_mutex);
+	i915_dereference_buffers_locked(dev_priv->buffers, num_buffers);
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
 static int i915_do_cleanup_pageflip(struct drm_device * dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -977,6 +1309,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
 	DRM_IOCTL_DEF(DRM_I915_MMIO, i915_mmio, DRM_AUTH),
 	DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
+	DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index 9976804..4ded5b4 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -160,6 +160,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_VBLANK_SWAP	0x0f
 #define DRM_I915_MMIO		0x10
 #define DRM_I915_HWS_ADDR	0x11
+#define DRM_I915_EXECBUFFER     0x12
 
 #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)
@@ -177,7 +178,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_SET_VBLANK_PIPE	DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_GET_VBLANK_PIPE	DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_VBLANK_SWAP	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
-
+#define DRM_IOCTL_I915_EXECBUFFER	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_EXECBUFFER, struct drm_i915_execbuffer)
 
 /* Asynchronous page flipping:
  */
@@ -325,4 +326,29 @@ typedef struct drm_i915_hws_addr {
 	uint64_t addr;
 } drm_i915_hws_addr_t;
 
+struct drm_i915_reloc {
+	uint32_t handle;
+	uint32_t offset;
+	uint32_t delta;
+};
+
+#define I915_RELOC_TYPE_0 0
+
+struct drm_i915_op_arg {
+	uint64_t next;
+	uint32_t reloc_handle;
+	int handled;
+	union {
+		struct drm_bo_op_req req;
+		struct drm_bo_arg_rep rep;
+	} d;
+
+};
+
+struct drm_i915_execbuffer {
+	struct _drm_i915_batchbuffer batch;
+	uint64_t ops_list;
+	struct drm_fence_arg fence_arg;
+};
+
 #endif				/* _I915_DRM_H_ */
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 3b26040..c86fd8a 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -65,6 +65,10 @@
 #endif
 #define DRIVER_PATCHLEVEL	0
 
+#ifdef I915_HAVE_BUFFER
+#define I915_NUM_VALIDATE_BUFFERS 256
+#endif
+
 typedef struct _drm_i915_ring_buffer {
 	int tail_mask;
 	unsigned long Start;
@@ -133,10 +137,12 @@ typedef struct drm_i915_private {
 #endif
 #ifdef I915_HAVE_BUFFER
 	void *agp_iomap;
+	struct drm_buffer_object *buffers[I915_NUM_VALIDATE_BUFFERS];
 #endif
 	DRM_SPINTYPE swaps_lock;
 	drm_i915_vbl_swap_t vbl_swaps;
 	unsigned int swaps_pending;
+
 } drm_i915_private_t;
 
 enum intel_chip_family {
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to