diff options
-rw-r--r-- | linux-core/r128_drv.c | 2 | ||||
-rw-r--r-- | linux/drm.h | 4 | ||||
-rw-r--r-- | linux/r128_dma.c | 203 | ||||
-rw-r--r-- | linux/r128_drv.c | 2 | ||||
-rw-r--r-- | linux/r128_drv.h | 4 | ||||
-rw-r--r-- | shared-core/drm.h | 4 | ||||
-rw-r--r-- | shared/drm.h | 4 |
7 files changed, 134 insertions, 89 deletions
diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index 374475b6..c00f2ff8 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -105,7 +105,7 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_W4IDLE)] = { r128_wait_idle, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_CCEIDL)] = { r128_cce_idle, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) diff --git a/linux/drm.h b/linux/drm.h index e816040e..fb073e1c 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -1,6 +1,6 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Sat Apr 15 01:40:31 2000 by kevin@precisioninsight.com + * Revised: Tue Apr 18 16:33:42 2000 by kevin@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. @@ -353,7 +353,7 @@ typedef struct drm_agp_info { /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) #define DRM_IOCTL_R128_RESET DRM_IO( 0x41) -#define DRM_IOCTL_R128_W4IDLE DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x42) #define DRM_IOCTL_R128_PACKET DRM_IOW( 0x43, drm_r128_packet_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x44, drm_r128_vertex_t) diff --git a/linux/r128_dma.c b/linux/r128_dma.c index 9c645b49..13506840 100644 --- a/linux/r128_dma.c +++ b/linux/r128_dma.c @@ -40,8 +40,6 @@ #define R128_MAX_VBUF_AGE 0x10000000 #define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 -extern int r128_do_engine_reset(drm_device_t *dev); - int R128_READ_PLL(drm_device_t *dev, int addr) { R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); @@ -214,7 +212,6 @@ static int r128_do_wait_for_fifo(drm_device_t *dev, int entries) if (slots >= entries) return 0; udelay(1); } - (void)r128_do_engine_reset(dev); return -EBUSY; } @@ -232,7 +229,6 @@ static int r128_do_wait_for_idle(drm_device_t *dev) } udelay(1); } - (void)r128_do_engine_reset(dev); return -EBUSY; } @@ -269,7 +265,7 @@ int r128_do_engine_reset(drm_device_t *dev) } /* Reset the CCE mode */ - r128_do_wait_for_idle(dev); + (void)r128_do_wait_for_idle(dev); R128_WRITE(R128_PM4_BUFFER_CNTL, dev_priv->cce_mode | dev_priv->ring_sizel2qw); (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ @@ -304,7 +300,6 @@ static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries) if (slots >= entries) return 0; udelay(1); } - (void)r128_do_engine_reset(dev); return -EBUSY; } @@ -329,7 +324,6 @@ int r128_do_cce_wait_for_idle(drm_device_t *dev) } udelay(1); } - (void)r128_do_engine_reset(dev); return -EBUSY; } else { int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size); @@ -342,13 +336,12 @@ int r128_do_cce_wait_for_idle(drm_device_t *dev) } udelay(1); } - (void)r128_do_engine_reset(dev); return -EBUSY; } } -int r128_wait_idle(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int r128_cce_idle(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -363,17 +356,19 @@ int r128_wait_idle(struct inode *inode, struct file *filp, } static int r128_submit_packets_ring_secure(drm_device_t *dev, - u32 *commands, int count) + u32 *commands, int *count) { drm_r128_private_t *dev_priv = dev->dev_private; int write = dev_priv->sarea_priv->ring_write; int *write_ptr = dev_priv->ring_start + write; + int c = *count; + int wrapped = 0; u32 tmp = 0; int psize = 0; int writing = 1; int timeout; - while (count > 0) { + while (c > 0) { tmp = *commands++; if (!psize) { writing = 1; @@ -411,23 +406,27 @@ static int r128_submit_packets_ring_secure(drm_device_t *dev, *write_ptr++ = tmp; } if (write >= dev_priv->ring_entries) { - write = 0; + write = 0; write_ptr = dev_priv->ring_start; + wrapped = 1; } timeout = 0; while (write == *dev_priv->ring_read_ptr) { (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); if (timeout++ >= dev_priv->usec_timeout) - return r128_do_engine_reset(dev); + return -EBUSY; udelay(1); } - count--; + c--; } - if (write < 32) { + if (wrapped) { + int size = write; + + if (size > 32) size = 32; memcpy(dev_priv->ring_end, dev_priv->ring_start, - write * sizeof(u32)); + size * sizeof(u32)); } /* Make sure WC cache has been flushed */ @@ -436,11 +435,13 @@ static int r128_submit_packets_ring_secure(drm_device_t *dev, dev_priv->sarea_priv->ring_write = write; R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + *count = 0; + return 0; } static int r128_submit_packets_pio_secure(drm_device_t *dev, - u32 *commands, int count) + u32 *commands, int *count) { u32 tmp = 0; int psize = 0; @@ -448,7 +449,7 @@ static int r128_submit_packets_pio_secure(drm_device_t *dev, int addr = R128_PM4_FIFO_DATA_EVEN; int ret; - while (count > 0) { + while (*count > 0) { tmp = *commands++; if (!psize) { writing = 1; @@ -488,7 +489,7 @@ static int r128_submit_packets_pio_secure(drm_device_t *dev, addr ^= 0x0004; } - count--; + *count -= 1; } if (addr == R128_PM4_FIFO_DATA_ODD) { @@ -500,34 +501,40 @@ static int r128_submit_packets_pio_secure(drm_device_t *dev, } static int r128_submit_packets_ring(drm_device_t *dev, - u32 *commands, int count) + u32 *commands, int *count) { drm_r128_private_t *dev_priv = dev->dev_private; int write = dev_priv->sarea_priv->ring_write; int *write_ptr = dev_priv->ring_start + write; + int c = *count; + int wrapped = 0; int timeout; - while (count > 0) { + while (c > 0) { write++; *write_ptr++ = *commands++; if (write >= dev_priv->ring_entries) { write = 0; write_ptr = dev_priv->ring_start; + wrapped = 1; } timeout = 0; while (write == *dev_priv->ring_read_ptr) { (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); if (timeout++ >= dev_priv->usec_timeout) - return r128_do_engine_reset(dev); + return -EBUSY; udelay(1); } - count--; + c--; } - if (write < 32) { + if (wrapped) { + int size = write; + + if (size > 32) size = 32; memcpy(dev_priv->ring_end, dev_priv->ring_start, - write * sizeof(u32)); + size * sizeof(u32)); } /* Make sure WC cache has been flushed */ @@ -536,25 +543,28 @@ static int r128_submit_packets_ring(drm_device_t *dev, dev_priv->sarea_priv->ring_write = write; R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + *count = 0; + return 0; } static int r128_submit_packets_pio(drm_device_t *dev, - u32 *commands, int count) + u32 *commands, int *count) { int ret; - while (count > 1) { + while (*count > 1) { if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); R128_WRITE(R128_PM4_FIFO_DATA_ODD, *commands++); - count -= 2; + *count -= 2; } - if (count) { + if (*count) { if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); R128_WRITE(R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2); + *count = 0; } return 0; @@ -563,22 +573,30 @@ static int r128_submit_packets_pio(drm_device_t *dev, static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count) { drm_r128_private_t *dev_priv = dev->dev_private; + int c = count; int ret; if (dev_priv->cce_is_bm_mode) { - if (dev_priv->cce_secure) - ret = r128_submit_packets_ring_secure(dev, buffer, count); - else - ret = r128_submit_packets_ring(dev, buffer, count); + int left = 0; + + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + left = count - c; + } + + /* Since this is only used by the kernel we can use the + insecure ring buffer submit packet routine */ + ret = r128_submit_packets_ring(dev, buffer, &c); + + c += left; } else { - if (dev_priv->cce_secure) - ret = r128_submit_packets_pio_secure(dev, - buffer, count); - else - ret = r128_submit_packets_pio(dev, buffer, count); + /* Since this is only used by the kernel we can use the + insecure PIO submit packet routine */ + ret = r128_submit_packets_pio(dev, buffer, &c); } - return ret; + if (ret < 0) return ret; + else return c; } int r128_submit_pkt(struct inode *inode, struct file *filp, @@ -589,7 +607,7 @@ int r128_submit_pkt(struct inode *inode, struct file *filp, drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_packet_t packet; u32 *buffer; - int count; + int c; int size; int ret = 0; @@ -602,41 +620,47 @@ int r128_submit_pkt(struct inode *inode, struct file *filp, copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet), -EFAULT); - count = packet.count; - size = count * sizeof(u32); + c = packet.count; + size = c * sizeof(*buffer); if (dev_priv->cce_is_bm_mode) { int left = 0; - if (count >= dev_priv->ring_entries) { - count = dev_priv->ring_entries-1; - left = packet.count - count; + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + size = c * sizeof(*buffer); + left = packet.count - c; } if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); if (dev_priv->cce_secure) - ret = r128_submit_packets_ring_secure(dev, - buffer, count); + ret = r128_submit_packets_ring_secure(dev, buffer, &c); else - ret = r128_submit_packets_ring(dev, buffer, count); + ret = r128_submit_packets_ring(dev, buffer, &c); - if (!ret) ret = left; + c += left; } else { if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); if (dev_priv->cce_secure) - ret = r128_submit_packets_pio_secure(dev, - buffer, count); + ret = r128_submit_packets_pio_secure(dev, buffer, &c); else - ret = r128_submit_packets_pio(dev, buffer, count); + ret = r128_submit_packets_pio(dev, buffer, &c); } kfree(buffer); - return ret; + packet.count = c; + copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet), + -EFAULT); + + if (ret) return ret; + else if (c > 0) return -EAGAIN; + + return 0; } static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) @@ -645,22 +669,17 @@ static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_buf_priv_t *buf_priv; drm_buf_t *buf; - int i; + int i, ret; u32 cce[2]; - if (++dev_priv->submit_age == R128_MAX_VBUF_AGE) { - dev_priv->submit_age = 0; - (void)r128_do_cce_wait_for_idle(dev); - r128_mark_vertbufs_done(dev); - } - + /* Make sure we have valid data */ for (i = 0; i < v->send_count; i++) { int idx = v->send_indices[i]; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", idx, dma->buf_count - 1); - continue; + return -EINVAL; } buf = dma->buflist[idx]; if (buf->pid != current->pid) { @@ -674,31 +693,55 @@ static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) v->send_indices[i], i); return -EINVAL; } - buf->pending = 1; - - /* FIXME: Add support for sending vertex buffer to the - CCE here instead of in client code. The v->prim - holds the primitive type that should be drawn. - - This will require us to loop over the clip rects here - as well, which implies that we extend the kernel - driver to allow cliprects to be stored here. Note - that the cliprects could possibly come from the X - server instead of the client, but this will require - additional changes to the DRI to allow for this - optimization. */ + } - buf_priv = buf->dev_private; - buf_priv->age = dev_priv->submit_age; + /* Wait for idle, if we've wrapped to make sure that all pending + buffers have been processed */ + if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { + if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret; + dev_priv->submit_age = 0; + r128_mark_vertbufs_done(dev); } /* Make sure WC cache has been flushed (if in PIO mode) */ if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); + /* FIXME: Add support for sending vertex buffer to the CCE here + instead of in client code. The v->prim holds the primitive + type that should be drawn. Loop over the list buffers in + send_indices[] and submit a packet for each VB. + + This will require us to loop over the clip rects here as + well, which implies that we extend the kernel driver to allow + cliprects to be stored here. Note that the cliprects could + possibly come from the X server instead of the client, but + this will require additional changes to the DRI to allow for + this optimization. */ + /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); cce[1] = dev_priv->submit_age; - r128_do_submit_packets(dev, cce, 2); + if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) { + /* Until we add support for sending VBs to the CCE in + this routine, we can recover from this error. After + we add that support, we won't be able to easily + recover, so we will probably have to implement + another mechanism for handling timeouts from packets + submitted directly by the kernel. */ + return ret; + } + + /* Now that the submit packet request has succeeded, we can mark + the buffers as pending */ + for (i = 0; i < v->send_count; i++) { + buf = dma->buflist[v->send_indices[i]]; + buf->pending = 1; + + buf_priv = buf->dev_private; + buf_priv->age = dev_priv->submit_age; + } + + dev_priv->submit_age++; return 0; } @@ -706,6 +749,7 @@ static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) static drm_buf_t *r128_freelist_get(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_buf_priv_t *buf_priv; drm_buf_t *buf; int i, t; @@ -718,7 +762,7 @@ static drm_buf_t *r128_freelist_get(drm_device_t *dev) if (buf->pid == 0) return buf; } - for (t = 0; t < 5; t++) { /* FIXME: Arbitrary */ + for (t = 0; t < dev_priv->usec_timeout; t++) { u32 done_age = R128_READ(R128_VB_AGE_REG); for (i = 0; i < dma->buf_count; i++) { @@ -731,6 +775,7 @@ static drm_buf_t *r128_freelist_get(drm_device_t *dev) return buf; } } + udelay(1); } return NULL; diff --git a/linux/r128_drv.c b/linux/r128_drv.c index 374475b6..c00f2ff8 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -105,7 +105,7 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_W4IDLE)] = { r128_wait_idle, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_CCEIDL)] = { r128_cce_idle, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) diff --git a/linux/r128_drv.h b/linux/r128_drv.h index c223694e..aa2a67a2 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -79,8 +79,8 @@ extern int r128_eng_reset(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int r128_submit_pkt(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int r128_wait_idle(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int r128_cce_idle(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/shared-core/drm.h b/shared-core/drm.h index e816040e..fb073e1c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1,6 +1,6 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Sat Apr 15 01:40:31 2000 by kevin@precisioninsight.com + * Revised: Tue Apr 18 16:33:42 2000 by kevin@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. @@ -353,7 +353,7 @@ typedef struct drm_agp_info { /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) #define DRM_IOCTL_R128_RESET DRM_IO( 0x41) -#define DRM_IOCTL_R128_W4IDLE DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x42) #define DRM_IOCTL_R128_PACKET DRM_IOW( 0x43, drm_r128_packet_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x44, drm_r128_vertex_t) diff --git a/shared/drm.h b/shared/drm.h index e816040e..fb073e1c 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -1,6 +1,6 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Sat Apr 15 01:40:31 2000 by kevin@precisioninsight.com + * Revised: Tue Apr 18 16:33:42 2000 by kevin@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. @@ -353,7 +353,7 @@ typedef struct drm_agp_info { /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) #define DRM_IOCTL_R128_RESET DRM_IO( 0x41) -#define DRM_IOCTL_R128_W4IDLE DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x42) #define DRM_IOCTL_R128_PACKET DRM_IOW( 0x43, drm_r128_packet_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x44, drm_r128_vertex_t) |