diff --git a/drivers/char/drm/i810.h b/drivers/char/drm/i810.h index ba40892f5d8a611fb6cbacb336403f35ba3ca711..a5d300a246fa2a6d78a40c8a11846a90a62eb781 100644 --- a/drivers/char/drm/i810.h +++ b/drivers/char/drm/i810.h @@ -55,9 +55,10 @@ * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility) * - Remove requirement for interrupt (leave stubs again) * 1.3 - Add page flipping. + * 1.4 - fix DRM interface */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 3 +#define DRIVER_MINOR 4 #define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index c21fc1c8ef2757e5896a8184f957ac8182b8be6e..7f65b110fce7d56b7daf71a2a6c64b138179e909 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -443,6 +443,49 @@ static int i810_dma_initialize(drm_device_t *dev, return 0; } +/* i810 DRM version 1.1 used a smaller init structure with different + * ordering of values than is currently used (drm >= 1.2). There is + * no defined way to detect the XFree version to correct this problem, + * however by checking using this procedure we can detect the correct + * thing to do. + * + * #1 Read the Smaller init structure from user-space + * #2 Verify the overlay_physical is a valid physical address, or NULL + * If it isn't then we have a v1.1 client. Fix up params. + * If it is, then we have a 1.2 client... get the rest of the data. + */ +int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg) +{ + + /* Get v1.1 init data */ + if (copy_from_user(init, (drm_i810_pre12_init_t *)arg, + sizeof(drm_i810_pre12_init_t))) { + return -EFAULT; + } + + if ((!init->overlay_physical) || (init->overlay_physical > 4096)) { + + /* This is a v1.2 client, just get the v1.2 init data */ + DRM_INFO("Using POST v1.2 init.\n"); + if(copy_from_user(init, (drm_i810_init_t *)arg, + sizeof(drm_i810_init_t))) { + return -EFAULT; + } + } else { + + /* This is a v1.1 client, fix the params */ + DRM_INFO("Using PRE v1.2 init.\n"); + init->pitch_bits = init->h; + init->pitch = init->w; + init->h = init->overlay_physical; + init->w = init->overlay_offset; + init->overlay_physical = 0; + init->overlay_offset = 0; + } + + return 0; +} + int i810_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -452,22 +495,46 @@ int i810_dma_init(struct inode *inode, struct file *filp, drm_i810_init_t init; int retcode = 0; - if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init))) + /* Get only the init func */ + if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t))) return -EFAULT; switch(init.func) { case I810_INIT_DMA: + /* This case is for backward compatibility. It + * handles XFree 4.1.0 and 4.2.0, and has to + * do some parameter checking as described below. + * It will someday go away. + */ + retcode = i810_dma_init_compat(&init, arg); + if (retcode) + return retcode; + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), DRM_MEM_DRIVER); - if(dev_priv == NULL) return -ENOMEM; + if (dev_priv == NULL) + return -ENOMEM; retcode = i810_dma_initialize(dev, dev_priv, &init); - break; + break; + + default: + case I810_INIT_DMA_1_4: + DRM_INFO("Using v1.4 init.\n"); + if (copy_from_user(&init, (drm_i810_init_t *)arg, + sizeof(drm_i810_init_t))) { + return -EFAULT; + } + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + DRM_INFO("DMA Cleanup\n"); retcode = i810_dma_cleanup(dev); - break; - default: - retcode = -EINVAL; - break; + break; } return retcode; @@ -477,12 +544,16 @@ int i810_dma_init(struct inode *inode, struct file *filp, /* Most efficient way to verify state for the i810 is as it is * emitted. Non-conformant state is silently dropped. + * + * Use 'volatile' & local var tmp to force the emitted values to be + * identical to the verified ones. */ static void i810EmitContextVerified( drm_device_t *dev, - unsigned int *code ) + volatile unsigned int *code ) { drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; + unsigned int tmp; RING_LOCALS; BEGIN_LP_RING( I810_CTX_SETUP_SIZE ); @@ -494,10 +565,12 @@ static void i810EmitContextVerified( drm_device_t *dev, OUT_RING( code[I810_CTXREG_ST1] ); for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) { - if ((code[i] & (7<<29)) == (3<<29) && - (code[i] & (0x1f<<24)) < (0x1d<<24)) + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) { - OUT_RING( code[i] ); + OUT_RING( tmp ); j++; } else printk("constext state dropped!!!\n"); @@ -514,6 +587,7 @@ static void i810EmitTexVerified( drm_device_t *dev, { drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; + unsigned int tmp; RING_LOCALS; BEGIN_LP_RING( I810_TEX_SETUP_SIZE ); @@ -524,11 +598,12 @@ static void i810EmitTexVerified( drm_device_t *dev, OUT_RING( code[I810_TEXREG_MI3] ); for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; - if ((code[i] & (7<<29)) == (3<<29) && - (code[i] & (0x1f<<24)) < (0x1d<<24)) + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) { - OUT_RING( code[i] ); + OUT_RING( tmp ); j++; } else printk("texture state dropped!!!\n"); @@ -556,9 +631,9 @@ static void i810EmitDestVerified( drm_device_t *dev, if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { OUT_RING( CMD_OP_DESTBUFFER_INFO ); OUT_RING( tmp ); - } - else - printk("buffer state dropped\n"); + } else + DRM_DEBUG("bad di1 %x (allow %x or %x)\n", + tmp, dev_priv->front_di1, dev_priv->back_di1); /* invarient: */ @@ -986,6 +1061,9 @@ int i810_dma_vertex(struct inode *inode, struct file *filp, return -EINVAL; } + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL; i810_dma_dispatch_vertex( dev, @@ -1034,6 +1112,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; + DRM_DEBUG("i810_swap_bufs\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_swap_buf called without lock held\n"); return -EINVAL; @@ -1081,6 +1161,9 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, retcode = i810_dma_get_buffer(dev, &d, filp); + DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", + current->pid, retcode, d.granted); + if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h index b35593bd41e9417fbbd3870d6bb46aa1d38471c5..c1d08efa736085dc0941aed7a40647d4791fd19a 100644 --- a/drivers/char/drm/i810_drm.h +++ b/drivers/char/drm/i810_drm.h @@ -94,12 +94,15 @@ #define I810_BACK 0x2 #define I810_DEPTH 0x4 +typedef enum _drm_i810_init_func { + I810_INIT_DMA = 0x01, + I810_CLEANUP_DMA = 0x02, + I810_INIT_DMA_1_4 = 0x03 + } drm_i810_init_func_t; +/* This is the init structure after v1.2 */ typedef struct _drm_i810_init { - enum { - I810_INIT_DMA = 0x01, - I810_CLEANUP_DMA = 0x02 - } func; + drm_i810_init_func_t func; #if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) int ring_map_idx; int buffer_map_idx; @@ -122,6 +125,24 @@ typedef struct _drm_i810_init { unsigned int pitch_bits; } drm_i810_init_t; +/* This is the init structure prior to v1.2 */ +typedef struct _drm_i810_pre12_init { + drm_i810_init_func_t func; + unsigned int mmio_offset; + unsigned int buffers_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; +} drm_i810_pre12_init_t; + /* Warning: If you change the SAREA structure you must change the Xserver * structure as well */