diff options
author | Thomas White <taw@bitwiz.org.uk> | 2009-10-18 23:00:45 +0200 |
---|---|---|
committer | Thomas White <taw@bitwiz.org.uk> | 2009-10-22 00:33:47 +0200 |
commit | e05d2881be7db3f4e1a42440c809d3e18e406003 (patch) | |
tree | 1fb3da514a84f54ba37f2569c6e81b724310320a | |
parent | 464fc937c80ec25b1ac1a8c289a40a290e830e66 (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.c | 158 | ||||
-rw-r--r-- | drivers/mfd/glamo/glamo-cmdq.h | 2 | ||||
-rw-r--r-- | drivers/mfd/glamo/glamo-drm-drv.c | 1 | ||||
-rw-r--r-- | include/drm/glamo_drm.h | 17 |
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; |