aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2009-10-18 23:00:45 +0200
committerThomas White <taw@bitwiz.org.uk>2009-10-22 00:33:47 +0200
commite05d2881be7db3f4e1a42440c809d3e18e406003 (patch)
tree1fb3da514a84f54ba37f2569c6e81b724310320a
parent464fc937c80ec25b1ac1a8c289a40a290e830e66 (diff)
Add burst commands
This adds kernel support for sending burst commands to the hardware. Signed-off-by: Thomas White <taw@bitwiz.org.uk>
-rw-r--r--drivers/mfd/glamo/glamo-cmdq.c158
-rw-r--r--drivers/mfd/glamo/glamo-cmdq.h2
-rw-r--r--drivers/mfd/glamo/glamo-drm-drv.c1
-rw-r--r--include/drm/glamo_drm.h17
4 files changed, 178 insertions, 0 deletions
diff --git a/drivers/mfd/glamo/glamo-cmdq.c b/drivers/mfd/glamo/glamo-cmdq.c
index a96adc3cbd2..358a5186074 100644
--- a/drivers/mfd/glamo/glamo-cmdq.c
+++ b/drivers/mfd/glamo/glamo-cmdq.c
@@ -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)
diff --git a/drivers/mfd/glamo/glamo-cmdq.h b/drivers/mfd/glamo/glamo-cmdq.h
index 4c003c61181..d5a00e6ce7d 100644
--- a/drivers/mfd/glamo/glamo-cmdq.h
+++ b/drivers/mfd/glamo/glamo-cmdq.h
@@ -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,
diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c
index 1f1446659f5..c0c5c053268 100644
--- a/drivers/mfd/glamo/glamo-drm-drv.c
+++ b/drivers/mfd/glamo/glamo-drm-drv.c
@@ -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),
diff --git a/include/drm/glamo_drm.h b/include/drm/glamo_drm.h
index ecf35505837..4c194dcdf7d 100644
--- a/include/drm/glamo_drm.h
+++ b/include/drm/glamo_drm.h
@@ -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;