Add burst commands
authorThomas White <taw@bitwiz.org.uk>
Sun, 18 Oct 2009 21:00:45 +0000 (23:00 +0200)
committerThomas White <taw@bitwiz.org.uk>
Wed, 21 Oct 2009 22:33:47 +0000 (00:33 +0200)
This adds kernel support for sending burst commands to the hardware.

Signed-off-by: Thomas White <taw@bitwiz.org.uk>
drivers/mfd/glamo/glamo-cmdq.c
drivers/mfd/glamo/glamo-cmdq.h
drivers/mfd/glamo/glamo-drm-drv.c
include/drm/glamo_drm.h

index a96adc3..358a518 100644 (file)
@@ -333,6 +333,164 @@ cleanup:
 }
 
 
+/* Return true for a legal sequence of commands, otherwise false */
+static int glamo_sanitize_burst(u16 base, u16 *cmds, unsigned int count)
+{
+       /* XXX FIXME TODO: Implementation... */
+       return 1;
+}
+
+
+static int glamo_relocate_burst(struct glamodrm_handle *gdrm,
+                                drm_glamo_cmd_burst_t *cbuf, u16 *data,
+                                struct drm_device *dev,
+                                struct drm_file *file_priv)
+{
+       u32 *handles;
+       int *offsets;
+       int nobjs =  cbuf->nobjs;
+       int i;
+
+       if ( nobjs > 32 ) return -EINVAL;       /* Get real... */
+
+       handles = drm_alloc(nobjs*sizeof(u32), DRM_MEM_DRIVER);
+       if ( handles == NULL ) return -1;
+       if ( copy_from_user(handles, cbuf->objs, nobjs*sizeof(u32)) )
+               return -1;
+
+       offsets = drm_alloc(nobjs*sizeof(int), DRM_MEM_DRIVER);
+       if ( offsets == NULL ) return -1;
+       if ( copy_from_user(offsets, cbuf->obj_pos, nobjs*sizeof(int)) )
+               return -1;
+
+       for ( i=0; i<nobjs; i++ ) {
+
+               u32 handle = handles[i];
+               int offset = offsets[i];
+               struct drm_gem_object *obj;
+               struct drm_glamo_gem_object *gobj;
+               u32 addr;
+               u16 addr_low, addr_high;
+
+               if ( offset > cbuf->bufsz ) {
+                       printk(KERN_WARNING "[glamo-drm] Offset out of range"
+                                           " for this relocation!\n");
+                       goto fail;
+               }
+
+               obj = drm_gem_object_lookup(dev, file_priv, handle);
+               if ( obj == NULL ) return -1;
+
+               /* Unref the object now, or it'll never get freed.
+                * FIXME: This should really happen after the GPU has
+                * finished executing these commands. */
+               drm_gem_object_unreference(obj);
+
+               gobj = obj->driver_private;
+               if ( gobj == NULL ) {
+                       printk(KERN_WARNING "[glamo-drm] This object has no"
+                                           " private data!\n");
+                       goto fail;
+               }
+
+               addr = GLAMO_OFFSET_FB + gobj->block->start;
+               addr_low = addr & 0xffff;
+               addr_high = (addr >> 16) & 0x7f;
+               printk("low=0x%04x, high=0x%04x\n", addr_low, addr_high);
+
+               /* FIXME: Should really check that the register is a
+                * valid one for this relocation. */
+
+               printk("relocating at offset %i\n", offset);
+               printk("=%i\n", offset/2);
+               *(data+(offset/2)+0) = addr_low;
+               *(data+(offset/2)+1) = addr_high;
+
+       }
+
+       drm_free(handles, 1, DRM_MEM_DRIVER);
+       drm_free(offsets, 1, DRM_MEM_DRIVER);
+       return 0;
+
+fail:
+       drm_free(handles, 1, DRM_MEM_DRIVER);
+       drm_free(offsets, 1, DRM_MEM_DRIVER);
+       return -1;
+}
+
+
+/* This is DRM_IOCTL_GLAMO_CMDBURST */
+int glamo_ioctl_cmdburst(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       int ret = 0;
+       struct glamodrm_handle *gdrm;
+       drm_glamo_cmd_burst_t *cbuf = data;
+       u16 *burst;
+       size_t burst_size;
+       size_t data_size;
+       int i;
+
+       gdrm = dev->dev_private;
+
+       data_size = cbuf->bufsz;
+       burst_size = data_size + 4;  /* Add space for header */
+       if ( data_size % 4 ) burst_size += 2;
+       if ( burst_size > PAGE_SIZE ) return -EINVAL;
+       if ( burst_size % 4 ) return -EINVAL;
+
+       burst = drm_alloc(burst_size, DRM_MEM_DRIVER);
+       if ( burst == NULL ) return -ENOMEM;
+
+       /* Get data from userspace */
+       if ( copy_from_user(burst+2, cbuf->data, cbuf->bufsz) )         {
+               printk(KERN_WARNING "[glamo-drm] copy from user failed\n");
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       /* Sanitise */
+       if ( !glamo_sanitize_burst(cbuf->base, burst+2, cbuf->bufsz) ) {
+               printk(KERN_WARNING "[glamo-drm] sanitize buffer failed\n");
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       /* Relocate */
+       if ( cbuf->nobjs ) {
+               if ( glamo_relocate_burst(gdrm, cbuf, burst+2, dev, file_priv) )
+               {
+                       printk(KERN_WARNING "[glamo-drm] Relocation failed\n");
+                       ret = -EINVAL;
+                       goto cleanup;
+               }
+       }
+
+       /* Add burst header */
+       burst[0] = 1<<15 | cbuf->base;
+       burst[1] = data_size / 2;  /* -> 2-byte words */
+
+       /* Zero-pad if necessary */
+       if ( burst[1] & 0x01 ) {
+               burst[(burst_size/2)-1] = 0x0000;
+       }
+
+       for ( i=0; i<burst_size/2; i++ ) {
+               printk("0x%02x = %4i : %04x = %4i\n", i, i, burst[i], burst[i]);
+       }
+       goto cleanup;
+
+       /* Add to command queue */
+       glamo_add_to_ring(gdrm, burst, burst_size);
+       glamo_set_cmdq_irq(gdrm);
+
+cleanup:
+       drm_free(burst, 1, DRM_MEM_DRIVER);
+
+       return ret;
+}
+
+
 /* TODO: Banish this to the nether regions of Hades */
 static void glamo_cmdq_wait(struct glamodrm_handle *gdrm,
                             enum glamo_engine engine)
index 4c003c6..d5a00e6 100644 (file)
@@ -33,6 +33,8 @@
 
 extern int glamo_ioctl_cmdbuf(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
+extern int glamo_ioctl_cmdburst(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
 extern int glamo_ioctl_gem_wait_rendering(struct drm_device *dev, void *data,
                                           struct drm_file *file_priv);
 extern void glamo_cmdq_blank(struct glamodrm_handle *gdrm,
index 1f14466..c0c5c05 100644 (file)
@@ -63,6 +63,7 @@ static int glamo_ioctl_gem_info(struct drm_device *dev, void *data,
 struct drm_ioctl_desc glamo_ioctls[] = {
        DRM_IOCTL_DEF(DRM_GLAMO_CMDBUF, glamo_ioctl_cmdbuf, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_SWAP, glamo_ioctl_swap, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_GLAMO_CMDBURST, glamo_ioctl_cmdburst, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_INFO, glamo_ioctl_gem_info, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_CREATE, glamo_ioctl_gem_create, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_MMAP, glamo_ioctl_gem_mmap, DRM_AUTH),
index ecf3550..4c194dc 100644 (file)
@@ -42,6 +42,7 @@
 /* Glamo specific ioctls */
 #define DRM_GLAMO_CMDBUF     0x01
 #define DRM_GLAMO_SWAP       0x02
+#define DRM_GLAMO_CMDBURST   0x03
 
 #define DRM_GLAMO_GEM_INFO     0x1c
 #define DRM_GLAMO_GEM_CREATE   0x1d
@@ -54,6 +55,7 @@
 
 #define DRM_IOCTL_GLAMO_CMDBUF     DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_CMDBUF, drm_glamo_cmd_buffer_t)
 #define DRM_IOCTL_GLAMO_SWAP       DRM_IO(DRM_COMMAND_BASE + DRM_GLAMO_SWAP)
+#define DRM_IOCTL_GLAMO_CMDBURST     DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_CMDBURST, drm_glamo_cmd_burst_t)
 
 #define DRM_IOCTL_GLAMO_GEM_INFO   DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_INFO, struct drm_glamo_gem_info)
 #define DRM_IOCTL_GLAMO_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_CREATE, struct drm_glamo_gem_create)
@@ -64,6 +66,8 @@
 #define DRM_IOCTL_GLAMO_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_PWRITE, struct drm_glamo_gem_pwrite)
 #define DRM_IOCTL_GLAMO_GEM_WAIT_RENDERING DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_GEM_WAIT_RENDERING, struct drm_glamo_gem_wait_rendering)
 
+
+/* Simple command submission - a list of 16-bit address-data pairs */
 typedef struct drm_glamo_cmd_buffer {
        unsigned int bufsz;     /* Size of buffer, in bytes */
        char __user *buf;       /* Buffer of stuff to go onto the ring buffer */
@@ -74,6 +78,19 @@ typedef struct drm_glamo_cmd_buffer {
        struct drm_clip_rect __user *boxes;
 } drm_glamo_cmd_buffer_t;
 
+
+/* Burst command submission - base address and data:
+ *  - Data can be 32-bit (more easily)
+ *  - Easier for the kernel to validate */
+typedef struct drm_glamo_cmd_burst {
+       uint16_t base;          /* Base address (command) */
+       int bufsz;              /* Size of data, in bytes */
+       uint16_t *data;         /* Pointer to data */
+       unsigned int *obj_pos;  /* Offsets (in bytes) at which to put objs */
+       uint32_t *objs;         /* List of buffer object (handles) to use */
+       unsigned int nobjs;     /* Number of objects referenced */
+} drm_glamo_cmd_burst_t;
+
 struct drm_glamo_gem_info {
        uint64_t vram_start;
        uint64_t vram_size;