[updated patch attached]

Hmm, yes. Although that has been bumped recently it could be changed to
dynamic, though, but as Dave says,
we need to impose some kind of limit to avoid DOS.
Poulsbo is still using a buffer list from user-space, and there's an
internal kernel array that imposes this limit.

Okay the attached patch lets it dynamic up to 4096, and in theory we could make it a module parameter or settable via /sys, and possibly add a getparam for userspace to figure out what the limit is...

What's a bit different, though, is that the number of relocs is fixed
(by user space using a fixed-size
shared memory buffer for the relocs).

What I've done for the reloc numbers is allowed for one reloc per 4-dwords in a batchbuffer in my Mesa code, and allocated that side.. granted it may not be that accurate it was just a rough heuristic..

However I have allowed for chaining reloc buffers in the interface if not in the implementation, if you look are relocation buffer header, the first word is the relocation count and type of relocation and the second word is the buffer handle for another buffer of relocations... if this word contains !zero the code will look it another buffer of relocations.. I originally meant this for having different types of relocations but I could see how userspace could "ab"use this to get what you mentioned..

Dave.
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 4e73577..27bca52 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -1563,7 +1563,6 @@ int drm_bo_handle_validate(struct drm_file * file_priv, 
uint32_t handle,
                *bo_rep = bo;
        else
                drm_bo_usage_deref_unlocked(&bo);
-
        return ret;
 }
 EXPORT_SYMBOL(drm_bo_handle_validate);
diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c
index 75763e7..f3ba7ce 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 & (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..eeb6085 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -147,6 +147,10 @@ static int i915_initialize(struct drm_device * dev,
                return -EINVAL;
        }
 
+#ifdef I915_HAVE_BUFFER
+       dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS;
+#endif
+
        dev_priv->sarea_priv = (drm_i915_sarea_t *)
            ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
 
@@ -725,6 +729,344 @@ 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 %08lx", 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;
+}
+
+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;
+       uint32_t cur_handle = *reloc_buf_handle;
+       uint32_t *reloc_page;
+       int ret, reloc_is_iomem, reloc_stride;
+       uint32_t num_relocs, reloc_offset, reloc_end, reloc_page_offset, 
next_offset, cur_offset;
+       struct drm_bo_kmap_obj reloc_kmap;
+
+       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 = I915_RELOC0_STRIDE * sizeof(uint32_t); /* 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 = I915_RELOC0_HEADER * sizeof(uint32_t);
+       reloc_end = reloc_offset + (num_relocs * reloc_stride);
+
+       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;
+               } 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_buffer_object **buffers;
+       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; 
+
+       if (exec_buf->num_buffers > dev_priv->max_validate_buffers)
+               return -EINVAL;
+
+       num_buffers = exec_buf->num_buffers;
+
+       buffers = drm_calloc(num_buffers, sizeof(struct drm_buffer_object *), 
DRM_MEM_DRIVER);
+       if (!buffers)
+               return -ENOMEM;
+
+       /* validate buffer list + fixup relocations */
+       ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list,
+                                       buffers, &num_buffers);
+       if (ret) 
+               goto out_free;
+
+       /* submit buffer */
+       batch->start = 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(buffers, num_buffers);
+       mutex_unlock(&dev->struct_mutex);
+
+out_free:
+       drm_free(buffers, (exec_buf->num_buffers * sizeof(struct 
drm_buffer_object *)), DRM_MEM_DRIVER);
+
+       return ret;
+}
+
 static int i915_do_cleanup_pageflip(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -977,6 +1319,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..5716334 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,43 @@ 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
+
+/* type 0 relocation has a 4-uint32_t header,
+   0 - 16-bit type | 16 bit count
+   1 - buffer handle for another list of relocs
+   2-3 - spare.
+   The relocations are then 4-uint32_t strides
+   0 - offset into buffer
+   1 - delta to add in
+   2 - index into buffer list
+   3 - reserved (for optimisations later).
+*/
+#define I915_RELOC0_STRIDE 4
+#define I915_RELOC0_HEADER 4
+
+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 {
+       uint64_t ops_list;
+       uint32_t num_buffers;
+       struct _drm_i915_batchbuffer batch;
+       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..e8f1879 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -56,15 +56,20 @@
  * 1.8: New ioctl for ARB_Occlusion_Query
  * 1.9: Usable page flipping and triple buffering
  * 1.10: Plane/pipe disentangling
+ * 1.11: TTM superioctl
  */
 #define DRIVER_MAJOR           1
 #if defined(I915_HAVE_FENCE) && defined(I915_HAVE_BUFFER)
-#define DRIVER_MINOR           10
+#define DRIVER_MINOR           11
 #else
 #define DRIVER_MINOR           6
 #endif
 #define DRIVER_PATCHLEVEL      0
 
+#ifdef I915_HAVE_BUFFER
+#define I915_MAX_VALIDATE_BUFFERS 4096
+#endif
+
 typedef struct _drm_i915_ring_buffer {
        int tail_mask;
        unsigned long Start;
@@ -133,10 +138,13 @@ typedef struct drm_i915_private {
 #endif
 #ifdef I915_HAVE_BUFFER
        void *agp_iomap;
+       unsigned int max_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