patch-2.4.20 linux-2.4.20/drivers/char/drm/i810_dma.c
Next file: linux-2.4.20/drivers/char/drm/i810_drm.h
Previous file: linux-2.4.20/drivers/char/drm/gamma_dma.c
Back to the patch index
Back to the overall index
- Lines: 350
- Date:
Thu Nov 28 15:53:12 2002
- Orig file:
linux-2.4.19/drivers/char/drm/i810_dma.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/drivers/char/drm/i810_dma.c linux-2.4.20/drivers/char/drm/i810_dma.c
@@ -30,11 +30,12 @@
*
*/
-#define __NO_VERSION__
+#include <linux/config.h>
#include "i810.h"
#include "drmP.h"
#include "i810_drv.h"
#include <linux/interrupt.h> /* For task queue support */
+#include <linux/module.h>
/* in case we don't have a 2.3.99-pre6 kernel or later: */
#ifndef VM_DONTCOPY
@@ -73,7 +74,7 @@
*(volatile unsigned int *)(virt + outring) = n; \
outring += 4; \
outring &= ringmask; \
-} while (0);
+} while (0)
static inline void i810_print_status_page(drm_device_t *dev)
{
@@ -86,6 +87,7 @@
DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]);
DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]);
DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]);
+ DRM_DEBUG( "hw_status: Last Render: %x\n", temp[4]);
DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]);
for(i = 6; i < dma->buf_count + 6; i++) {
DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
@@ -182,11 +184,7 @@
if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
if(VM_DONTCOPY != 0) {
-#if LINUX_VERSION_CODE <= 0x020402
- down( ¤t->mm->mmap_sem );
-#else
down_write( ¤t->mm->mmap_sem );
-#endif
old_fops = filp->f_op;
filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf;
@@ -202,11 +200,7 @@
retcode = (signed int)buf_priv->virtual;
buf_priv->virtual = 0;
}
-#if LINUX_VERSION_CODE <= 0x020402
- up( ¤t->mm->mmap_sem );
-#else
up_write( ¤t->mm->mmap_sem );
-#endif
} else {
buf_priv->virtual = buf_priv->kernel_virtual;
buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -222,24 +216,11 @@
if(VM_DONTCOPY != 0) {
if(buf_priv->currently_mapped != I810_BUF_MAPPED)
return -EINVAL;
-#if LINUX_VERSION_CODE <= 0x020402
- down( ¤t->mm->mmap_sem );
-#else
down_write( ¤t->mm->mmap_sem );
-#endif
-#if LINUX_VERSION_CODE < 0x020399
- retcode = do_munmap((unsigned long)buf_priv->virtual,
- (size_t) buf->total);
-#else
retcode = do_munmap(current->mm,
(unsigned long)buf_priv->virtual,
(size_t) buf->total);
-#endif
-#if LINUX_VERSION_CODE <= 0x020402
- up( ¤t->mm->mmap_sem );
-#else
up_write( ¤t->mm->mmap_sem );
-#endif
}
buf_priv->currently_mapped = I810_BUF_UNMAPPED;
buf_priv->virtual = 0;
@@ -278,30 +259,6 @@
return retcode;
}
-static unsigned long i810_alloc_page(drm_device_t *dev)
-{
- unsigned long address;
-
- address = __get_free_page(GFP_KERNEL);
- if(address == 0UL)
- return 0;
-
- get_page(virt_to_page(address));
- LockPage(virt_to_page(address));
-
- return address;
-}
-
-static void i810_free_page(drm_device_t *dev, unsigned long page)
-{
- if (page) {
- struct page *p = virt_to_page(page);
- put_page(p);
- UnlockPage(p);
- free_page(page);
- }
-}
-
static int i810_dma_cleanup(drm_device_t *dev)
{
drm_device_dma_t *dma = dev->dma;
@@ -316,7 +273,8 @@
dev_priv->ring.Size);
}
if(dev_priv->hw_status_page != 0UL) {
- i810_free_page(dev, dev_priv->hw_status_page);
+ pci_free_consistent(dev->pdev, PAGE_SIZE, (void *)dev_priv->hw_status_page,
+ dev_priv->dma_status_page);
/* Need to rewrite hardware status page */
I810_WRITE(0x02080, 0x1ffff000);
}
@@ -474,12 +432,16 @@
dev_priv->back_offset = init->back_offset;
dev_priv->depth_offset = init->depth_offset;
+ dev_priv->overlay_offset = init->overlay_offset;
+ dev_priv->overlay_physical = init->overlay_physical;
+
dev_priv->front_di1 = init->front_offset | init->pitch_bits;
dev_priv->back_di1 = init->back_offset | init->pitch_bits;
dev_priv->zi1 = init->depth_offset | init->pitch_bits;
/* Program Hardware Status Page */
- dev_priv->hw_status_page = i810_alloc_page(dev);
+ dev_priv->hw_status_page = (unsigned long)pci_alloc_consistent(dev->pdev, PAGE_SIZE,
+ &dev_priv->dma_status_page);
if(dev_priv->hw_status_page == 0UL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
@@ -489,7 +451,7 @@
memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
- I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+ I810_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
/* Now we need to init our freelist */
@@ -505,6 +467,15 @@
return 0;
}
+#ifdef CONFIG_DRM_I810_XFREE_41
+int xfreeversion = 41;
+#else
+int xfreeversion = -1;
+#endif
+
+MODULE_PARM(xfreeversion, "i");
+MODULE_PARM_DESC(xfreeversion, "The version of XFree86 that needs to be supported");
+
int i810_dma_init(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -516,6 +487,28 @@
if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
return -EFAULT;
+
+ if ((xfreeversion == 41) ||
+ ((xfreeversion == -1) && (init.pitch == 0))) {
+ /*
+ * Ok we have a problem here. Someone decided it was
+ * funny to add two fields in the middle of the
+ * drm_i810_init_it structure in the transition between
+ * XFree86 4.1.0 and 4.2.0.
+ *
+ * The code below tries to fix this ABI breakage up as
+ * good as possible, unfortionatly it's impossible to
+ * autodetect which interface the user wants, hence the
+ * module parameter -- Arjan
+ */
+
+ 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;
+ }
switch(init.func) {
case I810_INIT_DMA:
@@ -1262,3 +1255,156 @@
if(VM_DONTCOPY == 0) return 1;
return 0;
}
+
+static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used,
+ unsigned int last_render)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ unsigned long address = (unsigned long)buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int u;
+ RING_LOCALS;
+
+ i810_kernel_lost_context(dev);
+
+ u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ I810_BUF_HARDWARE);
+ if(u != I810_BUF_CLIENT) {
+ DRM_DEBUG("MC found buffer that isn't mine!\n");
+ }
+
+ if (used > 4*1024)
+ used = 0;
+
+ sarea_priv->dirty = 0x7f;
+
+ DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n",
+ address, used);
+
+ dev_priv->counter++;
+ DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
+ DRM_DEBUG("i810_dma_dispatch_mc\n");
+ DRM_DEBUG("start : %lx\n", start);
+ DRM_DEBUG("used : %d\n", used);
+ DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
+
+ if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+ if (used & 4) {
+ *(u32 *)((u32)buf_priv->virtual + used) = 0;
+ used += 4;
+ }
+
+ i810_unmap_buffer(buf);
+ }
+ BEGIN_LP_RING(4);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + used - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+
+ BEGIN_LP_RING(8);
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( buf_priv->my_use_idx );
+ OUT_RING( I810_BUF_FREE );
+ OUT_RING( 0 );
+
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 16 );
+ OUT_RING( last_render );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
+
+int i810_dma_mc(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;
+ drm_device_dma_t *dma = dev->dma;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+ drm_i810_mc_t mc;
+
+ if (copy_from_user(&mc, (drm_i810_mc_t *)arg, sizeof(mc)))
+ return -EFAULT;
+
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_dma_mc called without lock held\n");
+ return -EINVAL;
+ }
+
+ i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
+ mc.last_render );
+
+ atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_inc(&dev->counts[_DRM_STAT_DMA]);
+ sarea_priv->last_enqueue = dev_priv->counter-1;
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return 0;
+}
+
+int i810_rstatus(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;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ return (int)(((u32 *)(dev_priv->hw_status_page))[4]);
+}
+
+int i810_ov0_info(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;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ drm_i810_overlay_t data;
+
+ data.offset = dev_priv->overlay_offset;
+ data.physical = dev_priv->overlay_physical;
+ copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
+ return 0;
+}
+
+int i810_fstatus(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;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_fstatus called without lock held\n");
+ return -EINVAL;
+ }
+ return I810_READ(0x30008);
+}
+
+int i810_ov0_flip(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;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_ov0_flip called without lock held\n");
+ return -EINVAL;
+ }
+
+ //Tell the overlay to update
+ I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000);
+
+ return 0;
+}
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)